LOADING REQUIREMENTS

PACKAGES

ENSEMBL

# ENSEMBL DATABASE
# v102 is for the latest mm10 version
# ensembl.v102 <- useMart(host = "https://nov2020.archive.ensembl.org",
#                        biomart = "ENSEMBL_MART_ENSEMBL",
#                        dataset = "mmusculus_gene_ensembl")

COLOR PALETTE

palette_1 = list(red = "#E9002D",
                 amber = "#FFAA00",
                 green = "#00B000")
palette_2 = list(red = "#FF1F5B",
                 green = "#00CD6C",
                 blue = "#009ADE",
                 purple = "#AF58BA",
                 yellow = "#FFC61E",
                 orange = "#F28522",
                 grey = "#A0B1BA",
                 brown = "#A6761D")
palette_3 = list(grey1 = "#a0b1ba",
                 grey2 = "#c5d0d5",
                 grey3 = "#eceff1")

colorListLoop <-  c(palette_3[["grey3"]], palette_3[["grey2"]], palette_3[["grey1"]],
                     "#C5E1EF", "#6CB0D6", "#226E9C",
                     "#06592A", 
                     "#FED976", "#FD8D3C", "#E31A1C")
colorListPromoter <- c(palette_3[["grey3"]],"#E88587", "#E31A1C")
colorListEnhancer <- c(palette_3[["grey3"]],"#87AFC7", "#226E9C")
colorListStructure <- c(palette_3[["grey3"]], palette_3[["grey2"]], palette_3[["grey1"]])

DIR LIST

# 
# loopDir <- here("../..", "result", "loop", "chromo_detect")
# scoreDir <- here("../..", "result", "loop", "chromo_quantify")
# consensusDir <- here("../..", "result", "loop", "consensus")
# figDir <- here("../..", "figure", "loop")
# refDir <- here("../..", "reference")

FIGURE PARAMETERS

library(colorspace)

fontType <- "Helvetica"

fontSizeL <- 10 # pt
fontSizeM <- 8
fontSizeS <- 6

lineThick <- 0.75 # pt
lineMedium <- 0.5
lineThin <- 0.25

panelUnit <- 30 # mm
panelMargin <- 1.5

mmToInch <- 0.03937007874
mmToLineUnit <- 1/2.13
mmToLinePlotgarden <- 1/0.75
ptToMM <- 1/2.845


strong_red <- "#CB333A"
strong_blue <- "#4851A0"
weak_red <- lighten(strong_red, amount = 0.4)   # FF7D81
weak_blue <- lighten(strong_blue, amount = 0.4) # 8A91DD
no_grey <- "#A8A8A8"

strong_teel <- "#0892A5"
strong_green <- "#23CE6B" # A485
strong_darkgreen <- "#054A29"
strong_yellow <- "#FFBA49"
strong_orange <- "#F18F01" # dTAG
strong_lightpurple <- "#BD93D8"
strong_purple <- "#9E33CB" # Epi

panelSize <- function(num, unit = panelUnit, margin = panelMargin){
  return(num*unit - 2*margin)
}

FUNCTIONS

importBedpe = function(bedpe){
  a1 = makeGRangesFromDataFrame(data.frame(
    chr = bedpe$V1,
    start = bedpe$V2 +1,
    end = bedpe$V3))
  a2 = makeGRangesFromDataFrame(data.frame(
    chr = bedpe$V4,
    start = bedpe$V5 +1,
    end = bedpe$V6))
  GInteractions(a1, a2)
}

get_density <- function(x, y, ...) {
  dens <- MASS::kde2d(x, y, ...)
  ix <- findInterval(x, dens$x)
  iy <- findInterval(y, dens$y)
  ii <- cbind(ix, iy)
  return(dens$z[ii])
}
label_kb_mb <- function(x) {
  ifelse(x >= 1000000, paste0(x / 1000000, "Mb"), paste0(x / 1000, "kb"))
}

importPeak = function(fileName){
  df = fread(fileName)
  gr = makeGRangesFromDataFrame(data.frame(
    chr = df$V1, start = df$V2, end = df$V3
  ))
}

Comparing G1 vs Async for consensus loops

All loops
diffCutoff = 0.2
data <- fread(here(consensusDir, "chromo_cons_score.tsv"))

temp <- fread(here(consensusDir, "chromo_cons_score_async.tsv")) %>%
  dplyr::select(id, UT, AID)

score.tb <- data %>% dplyr::full_join(temp, by = c("id")) %>%
  dplyr::mutate(diff_G1 = dTAG - DMSO,
                  diff_async = AID - UT)


### P1. UT vs AID
score.tb$density <- get_density(score.tb$UT, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$UT, score.tb$AID)
p1 <- ggplot(score.tb, aes(x = UT, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P1. DMSO vs dTAG
score.tb$density <- get_density(score.tb$DMSO, score.tb$dTAG, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$dTAG)
p2 <- ggplot(score.tb, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. DMSO vs A485
score.tb$density <- get_density(score.tb$DMSO, score.tb$A485, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$A485)
p3 <- ggplot(score.tb, aes(x = DMSO, y = A485, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. DMSO vs UT
score.tb$density <- get_density(score.tb$DMSO, score.tb$UT, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$UT)
p4 <- ggplot(score.tb, aes(x = DMSO, y = UT, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. dTAG vs AID
score.tb$density <- get_density(score.tb$dTAG, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$dTAG, score.tb$AID)
p5 <- ggplot(score.tb, aes(x = dTAG, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. diff
score.tb$density <- get_density(score.tb$diff_G1, score.tb$diff_async, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$diff_G1, score.tb$diff_async)
p6 <- ggplot(score.tb, aes(x = diff_G1, y = diff_async, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-1, 0.5) + ylim(-1, 0.5) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = -diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = -diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -1, y = 0.5, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


png(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync.png")), res = 600, units = "in", width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()
svglite(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync.svg")), width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()
reg loops
temp <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>%
  dplyr::mutate(res = V3 - V2,
                id = paste(V1, res, V2, V5, sep = "_"))
regID <- temp$id

diffCutoff = 0.2
data <- fread(here(consensusDir, "chromo_cons_score.tsv"))

temp <- fread(here(consensusDir, "chromo_cons_score_async.tsv")) %>%
  dplyr::select(id, UT, AID)

score.tb <- data %>% dplyr::full_join(temp, by = c("id")) %>%
  dplyr::mutate(diff_G1 = dTAG - DMSO,
                  diff_async = AID - UT) %>%
  dplyr::filter(id %in% regID)


### P1. UT vs AID
score.tb$density <- get_density(score.tb$UT, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$UT, score.tb$AID)
p1 <- ggplot(score.tb, aes(x = UT, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P1. DMSO vs dTAG
score.tb$density <- get_density(score.tb$DMSO, score.tb$dTAG, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$dTAG)
p2 <- ggplot(score.tb, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. DMSO vs A485
score.tb$density <- get_density(score.tb$DMSO, score.tb$A485, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$A485)
p3 <- ggplot(score.tb, aes(x = DMSO, y = A485, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. DMSO vs UT
score.tb$density <- get_density(score.tb$DMSO, score.tb$UT, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$UT)
p4 <- ggplot(score.tb, aes(x = DMSO, y = UT, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. dTAG vs AID
score.tb$density <- get_density(score.tb$dTAG, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$dTAG, score.tb$AID)
p5 <- ggplot(score.tb, aes(x = dTAG, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. diff
score.tb$density <- get_density(score.tb$diff_G1, score.tb$diff_async, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$diff_G1, score.tb$diff_async)
p6 <- ggplot(score.tb, aes(x = diff_G1, y = diff_async, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-1, 0.5) + ylim(-1, 0.5) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = -diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = -diffCutoff, alpha = 0.5, color = "grey") +
    theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -1, y = 0.5, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


png(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync_reg.png")), res = 600, units = "in", width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()
svglite(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync_reg.svg")), width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()


########## Saving Async and G1 specific regulatory loop
diffCutoff <- 0.2
temp <- score.tb %>% dplyr::filter(diff_G1 >= -diffCutoff, diff_async >= -diffCutoff) %>%
  dplyr::select(seq(1, 7))
fwrite(temp, here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_bothRetained.bedpe"), sep = "\t", col.names = FALSE)

temp <- score.tb %>% dplyr::filter(diff_G1 >= -diffCutoff, diff_async < -diffCutoff) %>%
  dplyr::select(seq(1, 7))
fwrite(temp, here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_AsyncSpecificPert.bedpe"), sep = "\t", col.names = FALSE)

temp <- score.tb %>% dplyr::filter(diff_G1 < -diffCutoff, diff_async >= -diffCutoff) %>%
  dplyr::select(seq(1, 7))
fwrite(temp, here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_G1SpecificPert.bedpe"), sep = "\t", col.names = FALSE)

temp <- score.tb %>% dplyr::filter(diff_G1 < -diffCutoff, diff_async < -diffCutoff) %>%
  dplyr::select(seq(1, 7))
fwrite(temp, here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_bothPert.bedpe"), sep = "\t", col.names = FALSE)
str loops
temp <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>%
  dplyr::mutate(res = V3 - V2,
                id = paste(V1, res, V2, V5, sep = "_"))
regID <- temp$id

diffCutoff = 0.2
data <- fread(here(consensusDir, "chromo_cons_score.tsv"))

temp <- fread(here(consensusDir, "chromo_cons_score_async.tsv")) %>%
  dplyr::select(id, UT, AID)

score.tb <- data %>% dplyr::full_join(temp, by = c("id")) %>%
  dplyr::mutate(diff_G1 = dTAG - DMSO,
                  diff_async = AID - UT) %>%
  dplyr::filter(id %in% regID)


### P1. UT vs AID
score.tb$density <- get_density(score.tb$UT, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$UT, score.tb$AID)
p1 <- ggplot(score.tb, aes(x = UT, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P1. DMSO vs dTAG
score.tb$density <- get_density(score.tb$DMSO, score.tb$dTAG, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$dTAG)
p2 <- ggplot(score.tb, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. DMSO vs A485
score.tb$density <- get_density(score.tb$DMSO, score.tb$A485, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$A485)
p3 <- ggplot(score.tb, aes(x = DMSO, y = A485, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. DMSO vs UT
score.tb$density <- get_density(score.tb$DMSO, score.tb$UT, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$DMSO, score.tb$UT)
p4 <- ggplot(score.tb, aes(x = DMSO, y = UT, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


### P3. dTAG vs AID
score.tb$density <- get_density(score.tb$dTAG, score.tb$AID, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$dTAG, score.tb$AID)
p5 <- ggplot(score.tb, aes(x = dTAG, y = AID, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

### P3. diff
score.tb$density <- get_density(score.tb$diff_G1, score.tb$diff_async, n = 100)
score.tb <- score.tb %>% dplyr::arrange(density)
correlation <- cor(score.tb$diff_G1, score.tb$diff_async)
p6 <- ggplot(score.tb, aes(x = diff_G1, y = diff_async, color = density)) +
  geom_point() + 
  scale_color_viridis() +
  xlim(-1, 0.5) + ylim(-1, 0.5) +
  coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_hline(yintercept = -diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = diffCutoff, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = -diffCutoff, alpha = 0.5, color = "grey") +
  theme_classic() + ggtitle(paste0("Consensus loop score")) +
  annotate("text", x = -1, y = 0.5, label = paste("r =", round(correlation, 2)), size = 5, color = "black")


png(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync_str.png")), res = 600, units = "in", width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()
svglite(here(figDir, paste0("consensus_score_scatterplot_pu100pz100_G1vsAsync_str.svg")), width = 5*2.5, height = 2.5*2.5)
print(cowplot::plot_grid(p1, p2, p3, 
                         p4, p5, p6, align = "h", ncol = 3))
dev.off()

Comparing loops called from Async

# Importing loops. For make comparison easier, 25 kb
binSize = 25*1000
temp <- fread(here(refDir, "Tjian_chromosight_loop.bedpe")) %>%
  dplyr::mutate(center1 = 0.5*(V2 + V3),
                center2 = 0.5*(V5 + V6),
                start1 = center1 - 0.5*binSize,
                end1 = center1 + 0.5*binSize,
                start2 = center2 - 0.5*binSize,
                end2 = center2 + 0.5*binSize) %>%
  dplyr::select(V1, start1, end1, V4, start2, end2)
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loop.async <- importBedpe(temp)


binSize = 25*1000
temp <- fread(here(consensusDir, "chromo_cons.bedpe")) %>%
  dplyr::mutate(center1 = 0.5*(V2 + V3),
                center2 = 0.5*(V5 + V6),
                start1 = center1 - 0.5*binSize,
                end1 = center1 + 0.5*binSize,
                start2 = center2 - 0.5*binSize,
                end2 = center2 + 0.5*binSize) %>%
  dplyr::select(V1, start1, end1, V4, start2, end2)
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loop.G1 <- importBedpe(temp)


# Check overlap
overlap <- findOverlaps(loop.async, loop.G1)


n.async <- nrow(as_tibble(loop.async))
n.G1 <- nrow(as_tibble(loop.G1))
n.async.overlap <- length(unique(queryHits(overlap)))
n.G1.overlap <- length(unique(subjectHits(overlap)))

plot(euler(c("Async" = n.async - n.async.overlap,
             "Async&G1" = n.async.overlap,
             "G1" = 1)), quantities = TRUE)


plot(euler(c("Async" =1,
             "Async&G1" = n.G1.overlap,
             "G1" = n.G1 - n.G1.overlap)), quantities = TRUE)




# Importing loops. For make comparison easier, 25 kb
binSize = 25*1000
temp.pp <- fread(here(refDir, "Tjian_chromosight_loop_P-P.bedpe")) %>%
  dplyr::mutate(center1 = 0.5*(V2 + V3),
                center2 = 0.5*(V5 + V6),
                start1 = center1 - 0.5*binSize,
                end1 = center1 + 0.5*binSize,
                start2 = center2 - 0.5*binSize,
                end2 = center2 + 0.5*binSize) %>%
  dplyr::select(V1, start1, end1, V4, start2, end2)
colnames(temp.pp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
binSize = 25*1000
temp.ep <- fread(here(refDir, "Tjian_chromosight_loop_E-P.bedpe")) %>%
  dplyr::mutate(center1 = 0.5*(V2 + V3),
                center2 = 0.5*(V5 + V6),
                start1 = center1 - 0.5*binSize,
                end1 = center1 + 0.5*binSize,
                start2 = center2 - 0.5*binSize,
                end2 = center2 + 0.5*binSize) %>%
  dplyr::select(V1, start1, end1, V4, start2, end2)
colnames(temp.ep) <- c("V1", "V2", "V3", "V4", "V5", "V6")
temp <- bind_rows(temp.pp, temp.ep)
loop.async <- importBedpe(temp)


binSize = 25*1000
temp <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>%
  dplyr::mutate(center1 = 0.5*(V2 + V3),
                center2 = 0.5*(V5 + V6),
                start1 = center1 - 0.5*binSize,
                end1 = center1 + 0.5*binSize,
                start2 = center2 - 0.5*binSize,
                end2 = center2 + 0.5*binSize) %>%
  dplyr::select(V1, start1, end1, V4, start2, end2)
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loop.G1 <- importBedpe(temp)


# Check overlap
overlap <- findOverlaps(loop.async, loop.G1)


n.async <- nrow(as_tibble(loop.async))
n.G1 <- nrow(as_tibble(loop.G1))
n.async.overlap <- length(unique(queryHits(overlap)))
n.G1.overlap <- length(unique(subjectHits(overlap)))

plot(euler(c("Async" = n.async - n.async.overlap,
             "Async&G1" = n.async.overlap,
             "G1" = 1)), quantities = TRUE)


plot(euler(c("Async" =0.1,
             "Async&G1" = n.G1.overlap,
             "G1" = n.G1 - n.G1.overlap)), quantities = TRUE)

[2.5] Consensus loop annotation

#### Importing ChIP-exo peaks
refDir <- here("../..", "reference")
peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
peak.H3K4me3 <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
peak.CTCF <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
peak.RAD21 <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))
peak.Whyte.SE <- importPeak(here(refDir, "superEnhancer_Whyte_ESC_mm10.bed"))
peak.Dylan.SE <- importPeak(here(refDir, "superEnhancer_Dylan_ESC.bed"))

Functions

createLoopAnnotation <- function(bedpe.loop.anno, name, figDir, outDir, colorList){
  temp = bedpe.loop.anno %>%
    dplyr::mutate(sample = name)
  
  num = nrow(temp)
  p7 = ggplot(temp, aes(x = sample, fill = Anno2)) +
    geom_bar(color = "black") +
    theme_bw() +
    labs(title = paste0(num, " loops"),
         x = "", y = "Counts") +
    scale_y_continuous(labels = comma_format()) +
    theme(plot.title = element_text(hjust = 0.5),
          aspect.ratio = 5,
          legend.position = "right",
          legend.direction  = "vertical") +
    scale_fill_manual(values = colorList)
  
  width = 3
  height = 5
  svglite(here(figDir,
               paste0("loopClassify_", name, ".svg")),
          width = width, height = height)
  plot(p7)
  invisible(dev.off())
  png(here(figDir,
           paste0("loopClassify_", name, ".png")),
      width = width, height = height, res = 600, units = "in")
  plot(p7)
  invisible(dev.off())
}


annotateLoopRelaxedTSS <- function(bedpe.anno){
  temp = bedpe.anno %>% dplyr::rowwise() %>%
    dplyr::mutate(
      A1 = if_else((A1_H3K4me3TSS), "P", 
                   if_else((A1_H3K27ac), "E",
                           if_else((A1_CTCF|A1_RAD21), "S", "X"))),
      A2 = if_else((A2_H3K4me3TSS), "P", 
                   if_else((A2_H3K27ac), "E",
                           if_else((A2_CTCF|A2_RAD21), "S", "X")))
    )
  temp = temp %>% dplyr::rowwise() %>%
    dplyr::mutate(Anno = paste0(A1, "-", A2),
                  Anno2 = if_else(Anno == "E-P", "P-E", 
                                  if_else(Anno == "S-P", "P-S",
                                          if_else(Anno == "X-P", "P-X",
                                                  if_else(Anno == "S-E", "E-S",
                                                          if_else(Anno == "X-E", "E-X",
                                                                  if_else(Anno == "X-S", "S-X",
                                                                          Anno)))))),
    )
  
  temp$Anno2 = factor(temp$Anno2, level = c("X-X",
                                            "S-X", "S-S",
                                            "E-X","E-S","E-E",
                                            "P-E","P-X", "P-S", "P-P"))
  
  # Checking the precense of super enhancer
  temp <- temp %>% dplyr::rowwise() %>%
    dplyr::mutate(AnnoSE = ifelse(A1_Whyte.SE | A2_Whyte.SE, "SE", "NO"))
  temp$AnnoSE <- factor(temp$AnnoSE, level = c("SE", "NO"))
  
  return(temp)
}

annotateLoopPromoterTSS <- function(bedpe.anno){
  temp = bedpe.anno %>% dplyr::rowwise() %>%
    dplyr::mutate(
      A1 = if_else((A1_H3K4me3TSS), "P", "N"),
      A2 = if_else((A2_H3K4me3TSS), "P", "N")
    )
  temp = temp %>% dplyr::rowwise() %>%
    dplyr::mutate(Anno = paste0(A1, "-", A2),
                  Anno2 = if_else(Anno == "N-P", "P-N", Anno))
  
  temp$Anno2 = factor(temp$Anno2, level = c("N-N", "P-N", "P-P"))
  
  return(temp)
}

annotateLoopEnhancer <- function(bedpe.anno){
  temp = bedpe.anno %>% dplyr::rowwise() %>%
    dplyr::mutate(
      A1 = if_else((A1_H3K27ac), "E", "N"),
      A2 = if_else((A2_H3K27ac), "E", "N")
    )
  temp = temp %>% dplyr::rowwise() %>%
    dplyr::mutate(Anno = paste0(A1, "-", A2),
                  Anno2 = if_else(Anno == "N-E", "E-N", Anno))
  temp$Anno2 = factor(temp$Anno2, level = c("N-N", "E-N", "E-E"))
  
  return(temp)
}

annotateLoopStructure <- function(bedpe.anno){
  temp = bedpe.anno %>% dplyr::rowwise() %>%
    dplyr::mutate(
      A1 = if_else((A1_CTCF|A1_RAD21), "S", "N"),
      A2 = if_else((A2_CTCF|A2_RAD21), "S", "N")
    )
  temp = temp %>% dplyr::rowwise() %>%
    dplyr::mutate(Anno = paste0(A1, "-", A2),
                  Anno2 = if_else(Anno == "N-S", "S-N", Anno))
  temp$Anno2 = factor(temp$Anno2, level = c("N-N", "S-N", "S-S"))
  return(temp)
}


annotateAnchorTSS <- function(bedpe){
  tb.loop = 
    setOverlapColumn("Whyte.SE",
                     setOverlapColumn("CTCF",
                                      setOverlapColumn("RAD21",
                                                       setOverlapColumn("H3K27ac",
                                                                        setOverlapColumn("H3K4me3TSS", bedpe)))))
  return(tb.loop)
}

setOverlapColumn <- function(peakName, loop){
  tb.loop = as_tibble(loop)
  overlap = returnOverlapIndexLixt(get(paste0("peak.", peakName)), tb.loop)
  tb.loop[[paste0("A1_", peakName)]] = FALSE
  tb.loop[[paste0("A1_", peakName)]][overlap[[1]]] = TRUE
  tb.loop[[paste0("A2_", peakName)]] = FALSE
  tb.loop[[paste0("A2_", peakName)]][overlap[[2]]] = TRUE
  return(tb.loop)
}

returnOverlapIndexLixt <- function(peak, loop){
  anchor1.tb = as_tibble(loop) %>% dplyr::select(chrom1, start1, end1)
  anchor1 = makeGRangesFromDataFrame(data.frame(
    chr = anchor1.tb$chrom1,
    start = anchor1.tb$start1,
    end = anchor1.tb$end1
  ))
  
  anchor2.tb = as_tibble(loop) %>% dplyr::select(chrom2, start2, end2)
  anchor2 = makeGRangesFromDataFrame(data.frame(
    chr = anchor2.tb$chrom2,
    start = anchor2.tb$start2,
    end = anchor2.tb$end2
  ))
  
  overlap = list(overlap1 = unique(queryHits(findOverlaps(anchor1, peak))),
                 overlap2 = unique(queryHits(findOverlaps(anchor2, peak))))
  return(overlap)
}

saveAnnoGroupBedpe <- function(temp, anno.list, name, annoName, ouDir){
  loop = temp %>% dplyr::filter(Anno2 %in% anno.list) %>%
    dplyr::select(c("chrom1", "start1", "end1", "chrom2", "start2", "end2"))
  fwrite(loop, here(outDir, paste0(name, "_", annoName, ".bedpe")), sep = "\t", col.names = FALSE)
}

Annotation

consensus.loop.tb <- fread(here(consensusDir, "chromo_cons_score.tsv"))

################################################################################
# Filtering H3K4me3 peaks that has TSS nearby
# Since the finest resolution is 5kb, +-2.5kb will be used as a cutoff for checking TSS presence
flankSize <- 2500
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend)
colnames(gene.tb) <- c("chr", "start", "end")
TSS1kb.gr <- makeGRangesFromDataFrame(gene.tb)
temp <- peak.H3K4me3[unique(queryHits(findOverlaps(peak.H3K4me3, TSS1kb.gr)))]
fwrite(as_tibble(temp), here(refDir, 
                             paste0("33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.", 
                                    flankSize/1000, "kbTSS.bed")), sep = "\t", col.names = FALSE)
peak.H3K4me3TSS <- importPeak(here(refDir, paste0("33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.", 
                                    flankSize/1000, "kbTSS.bed")))
################################################################################
# Annotating with strict priority (P-TSS > E > S)
temp.anno.TSS <- annotateAnchorTSS(consensus.loop.tb) %>%
  dplyr::mutate(
    diff_dTAG_DMSO = (dTAG-DMSO),
    diff_A485_DMSO = (A485-DMSO))

name <- "chromo_cons_annoHierarchy"
consensus.loop.anno.tb <- annotateLoopRelaxedTSS(temp.anno.TSS)
fwrite(consensus.loop.anno.tb, here(consensusDir, paste0(name, ".tsv")), 
       sep = "\t", col.names = TRUE)
createLoopAnnotation(consensus.loop.anno.tb, name, figDir, outDir,  colorListLoop)
saveAnnoGroupBedpe(consensus.loop.anno.tb, unique(consensus.loop.anno.tb$Anno2) , name, "all", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-P", "P-E", "P-S", "P-X", "E-E", "E-S", "E-X"), name, "regulatory", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("S-S", "S-X"), name, "structure", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("X-X"), name, "x-x", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-P", "P-E", "P-S", "P-X"), name, "p-n", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-P", "P-E", "E-E"), name, "pe-pe", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-P", "P-E"), name, "p-pe", outDir)

saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-P"), name, "p-p", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-E"), name, "p-e", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-S"), name, "p-s", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.tb, c("P-X"), name, "p-x", outDir)

################################################################################
# Annotating with one marker (Promoter)
name <- "chromo_cons_annoPromoter"
consensus.loop.anno.promoter.tb <- annotateLoopPromoterTSS(temp.anno.TSS)
fwrite(consensus.loop.anno.promoter.tb, here(consensusDir, paste0(name, ".tsv")), 
       sep = "\t", col.names = TRUE)
createLoopAnnotation(consensus.loop.anno.promoter.tb, name, 
                     figDir, outDir,  colorListPromoter)
saveAnnoGroupBedpe(consensus.loop.anno.promoter.tb, unique(consensus.loop.anno.promoter.tb$Anno2) , name, "all", outDir)  
saveAnnoGroupBedpe(consensus.loop.anno.promoter.tb, c("P-P"), name, "p-p", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.promoter.tb, c("P-N"), name, "p-n", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.promoter.tb, c("N-N"), name, "n-n", outDir)

################################################################################
# Annotating with one marker (Enhancer)
name <- "chromo_cons_annoEnhancer"
consensus.loop.anno.enhancer.tb <- annotateLoopEnhancer(temp.anno.TSS)
fwrite(consensus.loop.anno.enhancer.tb, here(consensusDir, paste0(name, ".tsv")), 
       sep = "\t", col.names = TRUE)
createLoopAnnotation(consensus.loop.anno.enhancer.tb, name, 
                     figDir, outDir,  colorListEnhancer)
saveAnnoGroupBedpe(consensus.loop.anno.enhancer.tb, unique(consensus.loop.anno.enhancer.tb$Anno2) , name, "all", outDir)  
saveAnnoGroupBedpe(consensus.loop.anno.enhancer.tb, c("E-E"), name, "e-e", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.enhancer.tb, c("E-N"), name, "e-n", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.enhancer.tb, c("N-N"), name, "n-n", outDir)
################################################################################
# Annotating with one marker (Structure)
name <- "chromo_cons_annoStructure"
consensus.loop.anno.structure.tb <- annotateLoopStructure(temp.anno.TSS)
fwrite(consensus.loop.anno.structure.tb, here(consensusDir, paste0(name, ".tsv")), 
       sep = "\t", col.names = TRUE)
createLoopAnnotation(consensus.loop.anno.structure.tb, name, 
                     figDir, outDir,  colorListStructure)
saveAnnoGroupBedpe(consensus.loop.anno.structure.tb, unique(consensus.loop.anno.structure.tb$Anno2) , name, "all", outDir)  
saveAnnoGroupBedpe(consensus.loop.anno.structure.tb, c("S-S"), name, "s-s", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.structure.tb, c("S-N"), name, "s-n", outDir)
saveAnnoGroupBedpe(consensus.loop.anno.structure.tb, c("N-N"), name, "n-n", outDir)
Pure-reg vs Str-reg
################################################################################
# 2024.09.10 Splitting regulatory loop into pure regulatory and structure-related loops
name <- "chromo_cons_annoHierarchy"
consensus.loop.anno.tb <- fread(here(consensusDir, paste0(name, ".tsv")))
regulatory.loop.anno.tb <- consensus.loop.anno.tb %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))

regulatory.loop.anno.tb <- regulatory.loop.anno.tb %>% rowwise() %>%
  dplyr::mutate(
    Anno3 = ifelse(A1_RAD21 | A1_CTCF | A2_RAD21 | A2_RAD21, paste0("str"),
                   paste0("reg"))
  )


fwrite(regulatory.loop.anno.tb, here(consensusDir, paste0(name, "_Anno3.tsv")), 
       sep = "\t", col.names = TRUE)

regulatory.loop.anno.tb_reg <- regulatory.loop.anno.tb %>% dplyr::filter(Anno3 == "reg")
regulatory.loop.anno.tb_str <- regulatory.loop.anno.tb %>% dplyr::filter(Anno3 == "str")

saveAnnoGroupBedpe(regulatory.loop.anno.tb_reg, c("P-P", "P-E", "E-E"), name, "pe-pe_reg", outDir)
saveAnnoGroupBedpe(regulatory.loop.anno.tb_str, c("P-P", "P-E", "E-E"), name, "pe-pe_str", outDir)

[2.6] Comparing across samples for conesnsus loop

Functions

create_loop_dis_vs_score <- function(data, figDir, name, Anno2List){
  data = data %>% dplyr::filter(Anno2 %in% Anno2List)
  
  ### barplot
  temp <- data %>% dplyr::select(id, DMSO, dTAG, A485) %>%
    pivot_longer(!id, names_to = "treatment", values_to = "score")
  temp$treatment <- factor(temp$treatment, levels = c("DMSO", "dTAG", "A485"))
  
  p3 <- ggplot(temp, aes(x = treatment, y = score)) +
    geom_violin(aes(fill = treatment), show.legend = FALSE) +
    scale_fill_manual(values = c("DMSO" = "grey", "dTAG" = "pink", "A485" = "skyblue")) +
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    ylim(-0.5, 1) +
    geom_hline(yintercept = 0, linetype = "dashed", color = "grey") +
    theme_classic() +
    ggtitle(name) +
    theme(plot.title = element_text(size = 4))
  fileName <- paste0("score_barplot_", name)
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 2, height = 4)
  print(p3)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 2, height = 4)
  print(p3)
  dev.off()
  
  ### Distance vs score
  
  temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, dTAG, A485)

  avg_scores <- temp %>%
    group_by(distance) %>%
    summarise(across(starts_with("DMSO"):starts_with("A485"), mean, na.rm = TRUE))

  avg_scores_long <- avg_scores %>%
    pivot_longer(cols = DMSO:A485, names_to = "condition", values_to = "avg_score")
  avg_scores_long$condition <- factor(avg_scores_long$condition, levels = c("DMSO", "dTAG", "A485"))
  # Create the plot
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = condition, fill = condition)) +
    geom_smooth(show.legend = TRUE) + ylim(0, 0.5) +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = c("DMSO" = "grey", "dTAG" = "pink", "A485" = "skyblue")) +
    scale_fill_manual(values = c("DMSO" = "grey80", "dTAG" = "pink", "A485" = "skyblue")) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Score") +
    theme(plot.title = element_text(size = 5))
  fileName <- paste0("dist_vs_score_linePlot_", name)
  png(here(figDir, paste0(fileName, ".png")),
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),
      width = 4, height = 3)
  print(p4)
  dev.off()
}

create_loop_dis_vs_diffscore <- function(data, figDir, name, Anno2List){
  data = data %>% dplyr::filter(Anno2 %in% Anno2List)
  
  
  temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_dTAG_DMSO, diff_A485_DMSO)
  
  avg_scores <- temp %>%
    group_by(distance) %>%
    summarise(across(1:2, mean, na.rm = TRUE))
  
  avg_scores_long <- avg_scores %>%
    pivot_longer(cols = 2:3, names_to = "condition", values_to = "avg_score")
  avg_scores_long$condition <- factor(avg_scores_long$condition, 
                                      levels = c("diff_dTAG_DMSO", "diff_A485_DMSO"))
  # Create the plot
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = condition, fill = condition)) +
    geom_smooth(show.legend = TRUE) + geom_hline(yintercept = 0) + ylim(-0.5, 0.1) +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = c("diff_dTAG_DMSO" = "pink", "diff_A485_DMSO" = "skyblue")) +
    scale_fill_manual(values = c("diff_dTAG_DMSO" = "pink", "diff_A485_DMSO" = "skyblue")) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Diff Score") +
    theme(plot.title = element_text(size = 5))
  fileName <- paste0("dist_vs_score_difflinePlot_", name)
  png(here(figDir, paste0(fileName, ".png")),
      res = 600, units = "in", width = 4.5, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),
          width = 4.5, height = 3)
  print(p4)
  dev.off()
}

create_loop_scatterplot <- function(data, figDir, name, Anno2List, diffCutoff){
  data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN"))) %>%
    dplyr::filter(Anno2 %in% Anno2List)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  num.up <- (summary(data$updown_dTAG_DMSO))["UP"]
  num.no <- (summary(data$updown_dTAG_DMSO))["NO"]
  num.down <- (summary(data$updown_dTAG_DMSO))["DOWN"]
  num.all <- num.up + num.no + num.down
  perc.up <- round(num.up / num.all * 100, 2)
  perc.no <- round(num.no / num.all * 100, 2)
  perc.down <- round(num.down / num.all * 100, 2)
  
  ### Scatterplot
  data$density <- get_density(data$DMSO, data$dTAG, n = 100)
  data <- data %>% dplyr::arrange(density)
  correlation <- cor(data$DMSO, data$dTAG)
  p1 <- ggplot(data, aes(x = DMSO, y = dTAG, color = density)) +
    geom_point(size = 1,
      alpha = 1,
      stroke = 0) + 
    scale_color_viridis(option = "D", guide = guide_colorbar(
                          barwidth = 1.5/5.08,  # Adjust width of the color bar
                          barheight = 15/5.08   # Adjust height of the color bar
                        )) +
    xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
             color = "black", hjust = 0, , size = 1,
        family = fontType) +
    annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
             color = "black", hjust = 0, , size = 1,
        family = fontType) +
    annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
             color = "black", hjust = 0, , size = 1,
        family = fontType) +
    theme_classic() +
    #annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black") +
    theme(
      # legend.position = "none",
      plot.title = element_text(
        hjust = 0.5,
        size = fontSizeS,
        family = fontType
      ),
      axis.title = element_text(
        size = fontSizeS,
        family = fontType,
        color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeS,
        family = fontType,
        color = "#000000"
      ),
      axis.line = element_line(
        color = "#000000",
        size = lineThick*mmToLineUnit,
        lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000",
        size = lineThick*mmToLineUnit,
        lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
    ) +
  xlab("Loop score\nG1.DMSO") +
    ylab("Loop score\nG1.dTAG")
  
  
  
  num.up <- (summary(data$updown_A485_DMSO))["UP"]
  num.no <- (summary(data$updown_A485_DMSO))["NO"]
  num.down <- (summary(data$updown_A485_DMSO))["DOWN"]
  num.all <- num.up + num.no + num.down
  perc.up <- round(num.up / num.all * 100, 2)
  perc.no <- round(num.no / num.all * 100, 2)
  perc.down <- round(num.down / num.all * 100, 2)
  
  data$density <- get_density(data$DMSO, data$A485, n = 100)
  data <- data %>% dplyr::arrange(density)
  correlation <- cor(data$DMSO, data$A485)
  p2 <- ggplot(data, aes(x = DMSO, y = A485, color = density)) +
    geom_point(size = 1,
      alpha = 1,
      stroke = 0) + 
    scale_color_viridis(option = "D", guide = guide_colorbar(
                          barwidth = 1.5/5.08,  # Adjust width of the color bar
                          barheight = 15/5.08   # Adjust height of the color bar
                        )) +
    xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey",
      color = "black",
      size = lineThick*mmToLineUnit,
      lineend = "square") +
    annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
             color = "black", hjust = 0, size = 1,
        family = fontType) +
    annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
             color = "black", hjust = 0, size = 1,
        family = fontType) +
    annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
             color = "black", hjust = 0, size = 1,
        family = fontType) +
    theme_classic() + 
    # annotate("text", x = -0.5, y = 1, label = paste("r =", round(correlation, 2)), size = 5, color = "black") +
    theme(
      # legend.position = "none",
      plot.title = element_text(
        hjust = 0.5,
        size = fontSizeS,
        family = fontType
      ),
      axis.title = element_text(
        size = fontSizeS,
        family = fontType,
        color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeS,
        family = fontType,
        color = "#000000"
      ),
      axis.line = element_line(
        color = "#000000",
        size = lineThick*mmToLineUnit,
        lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000",
        size = lineThick*mmToLineUnit,
        lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
    ) +
    xlab("Loop score\nG1.DMSO") +
    ylab("Loop score\nG1.A485")

    width <- panelSize(1.5)*mmToInch
  height <- panelSize(1.5)*mmToInch  
  
  fileName <- here(figDir,paste0("scatterplot_", name, "_dTAG_vs_DMSO_", diffCutoff))

  svglite(paste0(fileName, ".svg"), width = width, height =height)
  print(p1)
  dev.off()
  png(paste0(fileName, ".png"), width = width, height =height, res = 600, unit = "in")
  print(p1)
  dev.off()
  
    fileName <- here(figDir, paste0("scatterplot_", name, "_A485_vs_DMSO_", diffCutoff))

  svglite(paste0(fileName, ".svg"), width = width, height =height)
  print(p2)
  dev.off()
  png(paste0(fileName, ".png"), width = width, height =height, res = 600, unit = "in")
  print(p2)
  dev.off()
  
  # 
  # 
  # 
  # png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 5*1.5, height = 2.5*1.5)
  # print(cowplot::plot_grid(p1, p2, align = "h"))
  # dev.off()
  # 
  # svglite(here(figDir, paste0(fileName, ".svg")), 
  #         width = 5*1.5, height = 2.5*1.5)
  # print(cowplot::plot_grid(p1, p2, align = "h"))
  # dev.off()
}

make_diff_bedpe <- function(data, name, Anno2List, outDir, diffCutoff){
  data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN"))) %>%
    dplyr::filter(Anno2 %in% Anno2List)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "UP") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_UP_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "NO") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_NO_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "DOWN") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_DOWN_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "UP") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_UP_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "NO") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_NO_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "DOWN") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_DOWN_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
}

create_dist_vs_avgScore_perTreatment <- function(data, figDir, name, loopList, colorList, se = FALSE){
  avg_scores_long <- data %>%
    group_by(distance, Anno2) %>%
    summarise(avg_score = mean(score, na.rm = TRUE)) %>%
    ungroup() 
  avg_scores_long$Anno2 <- factor(avg_scores_long$Anno2, level = loopList)
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = Anno2, fill = Anno2)) + 
    geom_smooth(show.legend = TRUE, se = se)  +
    ylim(0, 0.5) +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = colorList) +
    scale_fill_manual(values = colorList) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Score") +
    theme(plot.title = element_text(size = 8))
  
  fileName <- paste0("dist_vs_score_linePlot_", name)
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 4, height = 3)
  print(p4)
  dev.off()
} 

create_dist_vs_avgDiffScore_perTreatment <- function(data, figDir, name, loopList, colorList, se = FALSE){
  avg_scores_long <- data %>%
    group_by(distance, Anno2) %>%
    summarise(avg_score = mean(score, na.rm = TRUE)) %>%
    ungroup() 
  avg_scores_long$Anno2 <- factor(avg_scores_long$Anno2, level = loopList)
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = Anno2, fill = Anno2)) + 
    geom_hline(yintercept = 0) +
    geom_smooth(show.legend = TRUE, se = se)  +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = colorList) +
    scale_fill_manual(values = colorList) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Diff Score") +
    theme(plot.title = element_text(size = 8)) 
  
  fileName <- paste0("dist_vs_score_difflinePlot_", name)
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 4, height = 3)
  print(p4)
  dev.off()
} 

create_score_barplot_perTreatment <- function(data, figDir, name, loopList, colorList){
  data$Anno2 <- factor(data$Anno2, levels = loopList)
  
  p3 <- ggplot(data, aes(x = Anno2, y = score)) +
    geom_violin(aes(fill = Anno2), show.legend = FALSE) +
    scale_fill_manual(values = colorList) +
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    ylim(-0.5, 1) +
    geom_hline(yintercept = 0, linetype = "dashed", color = "grey") +
    theme_classic() +
    ggtitle(name) +
    theme(plot.title = element_text(size = 4))
  
  fileName <- paste0("score_barPlot_", name)
  
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 2, height = 4)
  print(p3)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 2, height = 4)
  print(p3)
}


iterate_loop_functions <- function(data, figDir, groupName, annoList){
  # create_loop_dis_vs_score(data, figDir, groupName, annoList)
  # create_loop_dis_vs_diffscore(data, figDir, groupName, annoList)

  create_loop_scatterplot(data, figDir, groupName, annoList, 0.2)
  # create_loop_scatterplot(data, figDir, groupName, annoList, 0.1)
  # make_diff_bedpe(data, groupName, annoList, consensusDir, 0.2)
  # make_diff_bedpe(data, groupName, annoList, consensusDir, 0.1)
}

Relaxed annotation


name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

iterate_loop_functions(data, figDir, paste0(name, "_", "cl_all"), unique(data$Anno2))
iterate_loop_functions(data, figDir, paste0(name, "_", "cl_structure"), 
                       c("S-S", "S-X"))
iterate_loop_functions(data, figDir, paste0(name, "_", "s-s"), 
                       c("S-S"))
iterate_loop_functions(data, figDir, paste0(name, "_", "cl_regulatory"), 
                       c("P-P", "P-E", "P-S", "P-X", "E-E", "E-S", "E-X"))
iterate_loop_functions(data, figDir, paste0(name, "_", "cl_pe-pe"), 
                       c("P-P", "P-E", "E-E"))
iterate_loop_functions(data, figDir, paste0(name, "_", "p-pe"), 
                       c("P-P", "P-E"))
iterate_loop_functions(data, figDir, paste0(name, "_", "p-p"), 
                       c("P-P"))
iterate_loop_functions(data, figDir, paste0(name, "_", "p-e"), 
                       c("P-E"))
iterate_loop_functions(data, figDir, paste0(name, "_", "e-e"), 
                       c("E-E"))
iterate_loop_functions(data, figDir, paste0(name, "_", "x-x"), 
                       c("X-X"))
###########
# Creating differential scatterplot
View(data)



#######################
# Creating figures per each condition
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_DMSO"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, A485, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_A485"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop)

#######################
# Creating figures per each condition, differential
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop)
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_dTAG_SE"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop, se = TRUE)
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_A485_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_A485"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop)

create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_A485_SE"), c("X-X",
                                                                 "S-X", "S-S",
                                                                 "E-X","E-S","E-E",
                                                                 "P-E","P-X", "P-S", "P-P"), colorListLoop, se = TRUE)
Pure-reg vs str-reg
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, "_Anno3.tsv")))
diffCutoff <- 0.2

# Splitting data
data.reg <- data %>% dplyr::filter(Anno3 == "reg")
data.str <- data %>% dplyr::filter(Anno3 == "str")

# Taking codes from previous function (str)
data <- data.str
data <- data %>%
  dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")))
data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))

num.up <- (summary(data$updown_dTAG_DMSO))["UP"]
num.no <- (summary(data$updown_dTAG_DMSO))["NO"]
num.down <- (summary(data$updown_dTAG_DMSO))["DOWN"]
num.all <- num.up + num.no + num.down
perc.up <- round(num.up / num.all * 100, 2)
perc.no <- round(num.no / num.all * 100, 2)
perc.down <- round(num.down / num.all * 100, 2)

data$density <- get_density(data$DMSO, data$dTAG, n = 100)
data <- data %>% dplyr::arrange(density)
p1 <- ggplot(data, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
           color = "black", hjust = 0, size = 3) +
  theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5))

# Taking codes from previous function (reg)
data <- data.reg
data <- data %>%
  dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")))
data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))

num.up <- (summary(data$updown_dTAG_DMSO))["UP"]
num.no <- (summary(data$updown_dTAG_DMSO))["NO"]
num.down <- (summary(data$updown_dTAG_DMSO))["DOWN"]
num.all <- num.up + num.no + num.down
perc.up <- round(num.up / num.all * 100, 2)
perc.no <- round(num.no / num.all * 100, 2)
perc.down <- round(num.down / num.all * 100, 2)

data$density <- get_density(data$DMSO, data$dTAG, n = 100)
data <- data %>% dplyr::arrange(density)
p2 <- ggplot(data, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
           color = "black", hjust = 0, size = 3) +
  theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5))  
  

fileName <- paste0("scatterplot_", name, "_", diffCutoff, "_pure_str_reg")
png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 5*1.5, height = 2.5*1.5)
print(cowplot::plot_grid(p1, p2, align = "h"))
dev.off()

svglite(here(figDir, paste0(fileName, ".svg")), 
        width = 5*1.5, height = 2.5*1.5)
print(cowplot::plot_grid(p1, p2, align = "h"))
dev.off()
50kb vs 200 kb
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, "_Anno3.tsv")))

data <- data %>% dplyr::mutate(size = start2 - start1)

data_under50kb <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"), size < 50*1000, Anno3 == "reg")
data_under200kb <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"), size >= 50*1000, size < 200*1000, Anno3 == "reg")
data_over200kb <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"), size >= 200*1000, Anno3 == "reg")

########

data <- data_under50kb

diffCutoff <- 0.2
data <- data %>%
  dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")))
data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))

####
num.up <- (summary(data$updown_dTAG_DMSO))["UP"]
num.no <- (summary(data$updown_dTAG_DMSO))["NO"]
num.down <- (summary(data$updown_dTAG_DMSO))["DOWN"]
num.all <- num.up + num.no + num.down
perc.up <- round(num.up / num.all * 100, 2)
perc.no <- round(num.no / num.all * 100, 2)
perc.down <- round(num.down / num.all * 100, 2)

data$density <- get_density(data$DMSO, data$dTAG, n = 100)
data <- data %>% dplyr::arrange(density)
p1 <- ggplot(data, aes(x = DMSO, y = dTAG, color = density)) +
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
           color = "black", hjust = 0, size = 3) +
  theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5))  
  

####
num.up <- (summary(data$updown_A485_DMSO))["UP"]
num.no <- (summary(data$updown_A485_DMSO))["NO"]
num.down <- (summary(data$updown_A485_DMSO))["DOWN"]
num.all <- num.up + num.no + num.down
perc.up <- round(num.up / num.all * 100, 2)
perc.no <- round(num.no / num.all * 100, 2)
perc.down <- round(num.down / num.all * 100, 2)

data$density <- get_density(data$DMSO, data$A485, n = 100)
data <- data %>% dplyr::arrange(density)
p2 <- ggplot(data, aes(x = DMSO, y = A485, color = density)) +
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() +
  xlim(-0.5, 1) + ylim(-0.5, 1) + coord_fixed() +
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
  geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  annotate("text", x = -0.5, y = 1, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
           color = "black", hjust = 0, size = 3) +
  annotate("text", x = -0.5, y = 1-0.2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
           color = "black", hjust = 0, size = 3) +
  theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5))  
  

fileName <- paste0("scatterplot_", name, "_", diffCutoff, "_regunder50kb_pure")
png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 5*1.5, height = 2.5*1.5)
print(cowplot::plot_grid(p1, p2, align = "h"))
dev.off()

svglite(here(figDir, paste0(fileName, ".svg")), 
        width = 5*1.5, height = 2.5*1.5)
print(cowplot::plot_grid(p1, p2, align = "h"))
dev.off()

One feature annotation - promoter


name <- "chromo_cons_annoPromoter"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
iterate_loop_functions(data, figDir, paste0(name, "_", "all"), unique(data$Anno2))
iterate_loop_functions(data, figDir, paste0(name, "_", "p-p"), c("P-P"))
iterate_loop_functions(data, figDir, paste0(name, "_", "p-n"), c("P-N"))
iterate_loop_functions(data, figDir, paste0(name, "_", "n-n"), c("N-N"))

colorList <- colorListPromoter
loopList <- c("N-N", "P-N", "P-P")

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)

create_score_barplot_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, A485, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                      loopList, colorList)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_A485_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)

One feature annotation - enhancer

name <- "chromo_cons_annoEnhancer"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
iterate_loop_functions(data, figDir, paste0(name, "_", "all"), unique(data$Anno2))
iterate_loop_functions(data, figDir, paste0(name, "_", "e-e"), c("E-E"))
iterate_loop_functions(data, figDir, paste0(name, "_", "e-n"), c("E-N"))
iterate_loop_functions(data, figDir, paste0(name, "_", "n-n"), c("N-N"))

colorList <- colorListEnhancer
loopList <- c("N-N", "E-N", "E-E")

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, A485, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                      loopList, colorList)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_A485_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)

One feature annotation - structure

name <- "chromo_cons_annoStructure"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
iterate_loop_functions(data, figDir, paste0(name, "_", "all"), unique(data$Anno2))
iterate_loop_functions(data, figDir, paste0(name, "_", "s-s"), c("S-S"))
iterate_loop_functions(data, figDir, paste0(name, "_", "s-n"), c("S-N"))
iterate_loop_functions(data, figDir, paste0(name, "_", "n-n"), c("N-N"))

colorList <- colorListStructure
loopList <- c("N-N", "S-N", "S-S")

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_DMSO"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                      loopList, colorList)
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, A485, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)
create_score_barplot_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                      loopList, colorList)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_dTAG"), 
                                     loopList, colorList, se = TRUE)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, diff_A485_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment(temp, figDir, paste0(name, "_A485"), 
                                     loopList, colorList, se = TRUE)

[2.7] Distance vs loop # and score

data <- fread(here(consensusDir, "chromo_cons_score.tsv")) %>%
  dplyr::mutate(distance = start2 - start1,
                res = end1 - start1)

p1 <- ggplot(data, aes(x = distance, fill = factor(res))) +
  geom_histogram(binwidth = 50000, alpha = 1) +
  labs(title = "Distribution of Distance by Resolution",
       x = "Distance",
       y = "Counts") + 
  facet_wrap(~ res, ncol = 1, scales = "free") + 
  scale_x_continuous(labels = label_kb_mb, limits = c(0, 5e6)) + 
  theme_classic() +
  theme(legend.position = "none",
        plot.title = element_text(size = 8))  # Removes the legend

png(here(figDir, paste0("consensus_dist_per_res.png")), 
    res = 600, units = "in", width = 3, height = 6)
print(p1)
dev.off()

p2 <- ggplot(data, aes(x = distance, fill = factor(res))) +
  geom_histogram(binwidth = 50000, alpha = 1) +
  labs(title = "Distribution of Distance by Resolution",
       x = "Distance",
       y = "Counts") + 
  facet_wrap(~ res, ncol = 1, scales = "free") + 
  scale_x_continuous(labels = label_kb_mb, limits = c(0, 2e6)) + 
  theme_classic() +
  theme(legend.position = "none",
        plot.title = element_text(size = 8))  # Removes the legend


png(here(figDir, paste0("consensus_dist_per_res_2mb.png")), 
    res = 600, units = "in", width = 3, height = 6)
print(p2)
dev.off()
### Distance vs score
  
  temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, DMSO, dTAG, A485)
  
  avg_scores <- temp %>%
    group_by(distance) %>%
    summarise(across(starts_with("DMSO"):starts_with("A485"), mean, na.rm = TRUE))
  
  avg_scores_long <- avg_scores %>%
    pivot_longer(cols = DMSO:A485, names_to = "condition", values_to = "avg_score")
  avg_scores_long$condition <- factor(avg_scores_long$condition, levels = c("DMSO", "dTAG", "A485"))
  # Create the plot
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = condition, fill = condition)) +
    geom_smooth(show.legend = TRUE) + ylim(0, 0.5) +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = c("DMSO" = "grey", "dTAG" = "pink", "A485" = "skyblue")) +
    scale_fill_manual(values = c("DMSO" = "grey80", "dTAG" = "pink", "A485" = "skyblue")) +
    labs(title = paste0("Distance vs. Average Score, ", note),
         x = "Distance",
         y = "Average Score") +
    theme(plot.title = element_text(size = 12))
  png(here(figDir, paste0("consensus_dist_vs_avgScore_allRes_pu100pz100_", note, ".png")), 
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()

[2.8] Annotating genes to P-P and P-E loops

[2.9] Size distribution of diff loops

create_dist_barplot <- function(data, figDir, name, note, loopList, diffCutoff){
  temp <- data %>% dplyr::select(Anno2, distance, updown_dTAG_DMSO, updown_A485_DMSO) %>%
    dplyr::filter(Anno2 %in% loopList,
                  updown_dTAG_DMSO %in% c("UP", "NO", "DOWN"))
  p <- ggplot(temp, aes(x = updown_dTAG_DMSO, y = distance)) +
    geom_violin(aes(fill = updown_dTAG_DMSO)) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = updown_dTAG_DMSO), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + ggtitle(note) +
    scale_y_continuous(labels = label_kb_mb)
  fileName <- paste0("size_barplot_", name, "_dTAG_vs_DMSO_", note, "_", diffCutoff)
  height <- 3
  width <- 4
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
  
  
  temp <- data %>% dplyr::select(Anno2, distance, updown_dTAG_DMSO, updown_A485_DMSO) %>%
    dplyr::filter(Anno2 %in% loopList,
                  updown_A485_DMSO %in% c("UP", "NO",  "DOWN"))
  p <- ggplot(temp, aes(x = updown_A485_DMSO, y = distance)) +
    geom_violin(aes(fill = updown_A485_DMSO)) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = updown_A485_DMSO), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + ggtitle(note) +
    scale_y_continuous(labels = label_kb_mb)
  fileName <- paste0("size_barplot_", name, "_A485_vs_DMSO_", note, "_", diffCutoff)
  height <- 3
  width <- 4
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}


name
diffCutoff <- 0.2
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
data <- data %>%
  dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                          ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")),
                distance = start2 - start1)
data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
create_dist_barplot(data, figDir, name, "p-n", c("P-P", "P-E", "P-S", "P-X"), 0.2)
create_dist_barplot(data, figDir, name, "p-pe", c("P-P", "P-E"), 0.2)
create_dist_barplot(data, figDir, name, "pe-pe", c("P-P", "P-E", "E-E"), 0.2)
create_dist_barplot(data, figDir, name, "str", c("S-S", "S-X"), 0.2)

[2.10] Linking with RNA-seq/PRO-seq

Function & parameter

GOdir <- here("../..", "result", "loop", "GO")
dir.create(GOdir, showWarnings = FALSE, recursive = TRUE)

getGO <- function(name, figDir, geneList, categoryNum = 15, height = 10, width = 7){
  GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
  GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)
  fwrite(as.data.frame(GO), here(GOdir, paste0("GO_", name, "_ensembl.tsv")), sep = "\t")
  fwrite(as.data.frame(GO.readable), here(GOdir, paste0("GO_", name, "_readable.tsv")), sep = "\t")
  
  if(nrow(as.data.frame(GO)) != 0){
    #####
    fileName <- paste0("GO_", name)
    svglite(here(figDir, paste0(fileName, ".svg")), height = height, width = width)
    print(dotplot(GO, showCategory = categoryNum, title = name) + 
            scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))
    dev.off()
    png(here(figDir, paste0(fileName, ".png")), height = height, width = width, res = 600, unit = "in")
    print(dotplot(GO, showCategory = categoryNum, title = name) + 
            scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))
    dev.off()
  } 
}

convPvalue <- function(pvalue){
  out <- ifelse(pvalue < 0.0001, "****",
                ifelse(pvalue < 0.001, "***",
                       ifelse(pvalue < 0.01, "**",
                              ifelse(pvalue < 0.05, "*", "ns"))))
  return(out)
}

loadLoopAnnoData <- function(fileName, diffCutoff = 0.2, annoList = c("P-P", "P-E", "P-S", "P-X")){
  data <- fread(fileName) %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")),
                  gene = strsplit(gene, '\\|')) %>%
    dplyr::filter(Anno2 %in%  annoList)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  return(data)
}

dTAG Scatterplot

loopType <- "p-n"

# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>%
  dplyr::mutate(distance = start2 - start1)
# geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
#                                       diffCutoff = diffCutoff,
#                                       annoList = c("P-P"))%>% 
#   dplyr::mutate(distance = start2 - start1)
# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

# 
# p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
#                       label = ifelse(flag != "0NO", external_gene_name, NA),
#                       shape = as.factor(maxFlag))) +
#   geom_point() + geom_text_repel() + theme_classic() + 
#   ggtitle("dTAG") +
#   geom_hline(yintercept = 0) +
#   geom_hline(yintercept = diffCutoff, linetype = "dashed") +
#   geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
#   geom_vline(xintercept = 0) +
#   geom_vline(xintercept = fcCutoff, linetype = "dashed") +
#   geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
#   scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
#   scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))
# 
# fileName <- paste0("log2FC_vs_avgScore_dTAG_", loopType, "_diffCutoff_", diffCutoff)
# height <- 4
# width <- 7
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

# fwrite(temp, here(consensusDir, paste0("gene_avgScore_fc_dTAG_", loopType, "_noFCcutoff.tsv")), sep = "\t")

p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point(size = 1, alpha = 1,
      stroke = 0) + geom_text_repel() + theme_classic() + 
  guides(color = "none", shape = "none") + 
  geom_hline(yintercept = 0, alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") +
  geom_hline(yintercept = c(diffCutoff, -diffCutoff), linetype = "dashed", alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") +
  geom_vline(xintercept = 0, alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") +
  geom_vline(xintercept = c(fcCutoff, -fcCutoff), linetype = "dashed", alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") +
  theme(
    axis.title.x = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) + labs(y = "Avg. Δ loop score", x = "log2(shrunken FC)") +
  scale_color_manual(values = c("0NO" = "#A9A8A9", "1UP" = "#CB333A", "2DOWN" = "#4852A0")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_", loopType, "_diffCutoff_", diffCutoff, "_noFCcutoff")
height <- 42*mmToInch
width <- 50*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - up and down
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.updown.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_", loopType, "_diffCutoff_", diffCutoff, "_noFCcutoffupdown")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# 
# ## RNA + PRO-seq
# temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, gene) %>% 
#   unnest(gene) %>% group_by(gene) %>%
#   summarize(mean_diff_score = mean(diff_dTAG_DMSO), .groups = 'drop')
# 
# temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
#   dplyr::mutate(flag = ifelse(gene %in% geneList.down, "2DOWN",
#                               ifelse(gene %in% geneList.up, "1UP", "0NO")),
#                 maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
#                 shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
#   dplyr::arrange(flag)
# 
# fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_", loopType, ".tsv"), sep = "\t")
# 
# p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
#                       label = ifelse(flag != "0NO", external_gene_name, NA),
#                       shape = as.factor(maxFlag))) +
#   geom_point() + geom_text_repel() + theme_classic() + 
#   ggtitle("dTAG") +
#   geom_hline(yintercept = 0) +
#   geom_hline(yintercept = diffCutoff, linetype = "dashed") +
#   geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
#   geom_vline(xintercept = 0) +
#   geom_vline(xintercept = fcCutoff, linetype = "dashed") +
#   geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
#   scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
#   scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))
# 
# fileName <- paste0("log2FC_vs_avgScore_dTAG_", loopType, "_diffCutoff_", diffCutoff, "_RNA-PRO")
# height <- 4
# width <- 7
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()

dTAG Scatterplot OE

Avg

loopType <- "p-pe"

# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)


# Loading OE loop score
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(log_obsexp_diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_", loopType, "_avgLogOE")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(log_obsexp_diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_", loopType, "_avgLogOE_noFCcutoff")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
Sum
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)


# Loading OE loop score
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = sum(log_obsexp_diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_sumLogOE")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = sum(log_obsexp_diff_dTAG_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_sumLogOE_noFCcutoff")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
abs max
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)


# Loading OE loop score
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO[which.max(abs(log_obsexp_diff_dTAG_DMSO))], .groups = 'drop')


temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_absLogOE")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO[which.max(abs(log_obsexp_diff_dTAG_DMSO))], .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_absLogOE_noFCcutoff")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
Closest P-N loop
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)


# Loading OE loop score
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene, distance) %>% 
  unnest(gene) %>% group_by(gene) %>% 
  slice_min(distance, with_ties = FALSE) %>% 
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO, .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_closestLogOE")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene, distance) %>% 
  unnest(gene) %>% group_by(gene) %>%
  slice_min(distance, with_ties = FALSE) %>% 
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO, .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_closestLogOE_noFCcutoff")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
Farthest P-N loop
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)


# Loading OE loop score
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id,
                          (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id))
geneList.down.RNA <- (diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.down.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff %>% dplyr::filter(shrinked_log2FC < 0))$ensembl_gene_id
geneList.updown.RNA.noFCcutoff <- (diff.RNA.G1.dTAG.noFCcutoff)$ensembl_gene_id

geneList.up <- unique(c((diff.RNA.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G1.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id,
                        (diff.PRO.G2.dTAG %>% dplyr::filter(shrinked_log2FC > 0))$ensembl_gene_id))


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 2

temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene, distance) %>% 
  unnest(gene) %>% group_by(gene) %>% 
  slice_max(distance, with_ties = FALSE) %>% 
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO, .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

#fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_farthestLogOE")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# No FC cutoff option - down only
temp <- geneAnnoData %>% dplyr::select(log_obsexp_diff_dTAG_DMSO, gene, distance) %>% 
  unnest(gene) %>% group_by(gene) %>%
  slice_max(distance, with_ties = FALSE) %>% 
  summarize(mean_diff_score = log_obsexp_diff_dTAG_DMSO, .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA.noFCcutoff, "2DOWN",
                              ifelse(gene %in% c(), "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)


p <- ggplot(temp, aes(x = shrinked_log2FC, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("dTAG") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "grey", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_dTAG_OE_p-n_farthestLogOE_noFCcutoff")
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

A485 Scatterplot

P-N
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.RNA.G1.A485 <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)

# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1)

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC < -fcCutoff))$ensembl_gene_id
geneList.up.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC > fcCutoff))$ensembl_gene_id


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_A485_p-n_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# [2] Sum of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(sum_diff_score = sum(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_sumScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = sum_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_sumScore_A485_p-n_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


# [3] Max of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(max_abs_diff_score = diff_A485_DMSO[which.max(abs(diff_A485_DMSO))], .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_maxAbsScore_fc_dTAG_p-n.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = max_abs_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_maxAbsScore_A485_p-n_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
P-PE
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.RNA.G1.A485 <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)

# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E"))%>% 
  dplyr::mutate(distance = start2 - start1)

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC < -fcCutoff))$ensembl_gene_id
geneList.up.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC > fcCutoff))$ensembl_gene_id


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-pe.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_A485_p-pe_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# [2] Sum of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(sum_diff_score = sum(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_sumScore_fc_dTAG_p-pe.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = sum_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_sumScore_A485_p-pe_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


# [3] Max of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(max_abs_diff_score = diff_A485_DMSO[which.max(abs(diff_A485_DMSO))], .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_maxAbsScore_fc_dTAG_p-pe.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = max_abs_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_maxAbsScore_A485_p-pe_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
P-S
# getting list of genes of interest from RNA-seq and PRO-seq
alpha <- 0.05
fcCutoff <- 0.5
diff.RNA.G1.A485 <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)

# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"

diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-S"))%>% 
  dplyr::mutate(distance = start2 - start1)

# Testing different ways to calculate representative feature of loops for each gene
diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
geneList.down.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC < -fcCutoff))$ensembl_gene_id
geneList.up.RNA <- (diff.RNA.G1.A485 %>% dplyr::filter(shrinked_log2FC > fcCutoff))$ensembl_gene_id


# [1] Average of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_avgScore_fc_dTAG_p-s.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = mean_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_avgScore_A485_p-s_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

# [2] Sum of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(sum_diff_score = sum(diff_A485_DMSO), .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_sumScore_fc_dTAG_p-s.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = sum_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_sumScore_A485_p-s_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


# [3] Max of differential loop scores for each gene
## RNA only
fcCutoff <- 0.5
alpha <- 0.05
maxLog2FC <- 4

temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(max_abs_diff_score = diff_A485_DMSO[which.max(abs(diff_A485_DMSO))], .groups = 'drop')

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% geneList.down.RNA, "2DOWN",
                              ifelse(gene %in% geneList.up.RNA, "1UP", "0NO")),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                shrlog2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag)

fwrite(temp, here(consensusDir, "gene_maxAbsScore_fc_dTAG_p-s.tsv"), sep = "\t")

p <- ggplot(temp, aes(x = shrlog2fcMax, y = max_abs_diff_score, color = flag, 
                      label = ifelse(flag != "0NO", external_gene_name, NA),
                      shape = as.factor(maxFlag))) +
  geom_point() + geom_text_repel() + theme_classic() + 
  ggtitle("A485") +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = diffCutoff, linetype = "dashed") +
  geom_hline(yintercept = - diffCutoff, linetype = "dashed") + 
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = fcCutoff, linetype = "dashed") +
  geom_vline(xintercept = -fcCutoff, linetype = "dashed") +
  scale_color_manual(values = c("0NO" = "black", "1UP" = "red", "2DOWN" = "blue")) +  # Corrected color mapping
  scale_shape_manual(values = c("TRUE" = 2, "FALSE" = 19))

fileName <- paste0("log2FC_vs_maxAbsScore_A485_p-s_diffCutoff_", diffCutoff)
height <- 4
width <- 7
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[2.11] How many loops per gene?

# IMPORTING GENE ANNO DATA FOR P-N LOOPS
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))


# Counting number of loop per genes
tempSum <- geneAnnoData %>% dplyr::select(peakID, gene, Anno2) %>% unnest(gene) %>% group_by(gene) %>%  summarize(
    peak = list(peakID),
    anno2 = list(Anno2),
    count = n())

ggplot(tempSum, aes(x = count)) + geom_histogram(binwidth = 1) + theme_classic() + 
  ggtitle("# of P-N loops for each gene") + scale_y_log10()

###################################################################################

[2.11.2] SuperEnhancer?

# IMPORTING GENE ANNO DATA FOR P-N LOOPS
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))

tempSE <- geneAnnoData %>% unnest(gene) %>% group_by(gene) %>% summarize(SE = ifelse(any(AnnoSE == "SE"), 1, 0))


group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene


tempSE <- tempSE %>% rowwise() %>% dplyr::mutate(
  group = ifelse(gene %in% group1, "group1",
                 ifelse(gene %in% group2, "group2",
                        ifelse(gene %in% group5, "group5",
                               ifelse(gene %in% group8, "group8", NA))))) %>% 
  dplyr::filter(!is.na(group))

perc.group1 <- nrow(tempSE %>% dplyr::filter(group == "group1", SE == 1))/
  nrow(tempSE %>% dplyr::filter(group == "group1"))

perc.group2 <- nrow(tempSE %>% dplyr::filter(group == "group2", SE == 1))/
  nrow(tempSE %>% dplyr::filter(group == "group2"))

perc.group5 <- nrow(tempSE %>% dplyr::filter(group == "group5", SE == 1))/
  nrow(tempSE %>% dplyr::filter(group == "group5"))

perc.group8 <- nrow(tempSE %>% dplyr::filter(group == "group8", SE == 1))/
  nrow(tempSE %>% dplyr::filter(group == "group8"))

tempPlot <- tibble(group = c("group1", "group2", "group5", "group8"),
                   perc = c(perc.group1, perc.group2, perc.group5, perc.group8))

ggplot(tempPlot, aes(x = group, y = perc)) + geom_point() + theme_classic() + ylim(0, 0.2)
plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO")

[2.12] How many loops/distance per gene in each quadrant?

dTAG with binary grouping

Splitting genes to group
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))


## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


temp <- temp %>%
  dplyr::mutate(group = ifelse(padj < 0.05 & shrinked_log2FC < 0, 1, 
                               ifelse(mean_diff_score < 0, 2, 3)))



fcCutoff <- 0.5
diffCutoff <- 0.2

gene.group1 <- (temp %>% dplyr::filter(group == 1))$gene
gene.group2 <- (temp %>% dplyr::filter(group == 2))$gene
fwrite((temp %>% dplyr::filter(group == 1)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 2)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"), sep = "\t")


# Adding group information to geneAnno
geneAnnoData <- geneAnnoData %>% unnest(gene) %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2", NA))
)
- GO for each group

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

GO1 <- enrichGO(gene = gene.group1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE)
GO2 <- enrichGO(gene = gene.group2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE)
GO1.df <- as.data.frame(GO1)
GO2.df <- as.data.frame(GO2)
# fwrite(GO1.df, here("GO_binary_group1.tsv"), sep = "\t")
# fwrite(GO2.df, here("GO_binary_group2.tsv"), sep = "\t")
GO1.df <- fread(here("GO_binary_group1.tsv"))
GO2.df <- fread(here("GO_binary_group2.tsv"))

subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 1") %>%
  dplyr::arrange(p.adjust)
subset1$GeneRatio <- sapply(strsplit(subset1$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))

subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 2") %>%
  dplyr::arrange(p.adjust)
subset2$GeneRatio <- sapply(strsplit(subset2$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))


GOlist <- factor(c("GO:0001824", "GO:0030879", "GO:0021953", "GO:0019827", 
                 "GO:0022613", "GO:0050767", "GO:0034470", "GO:0016055", 
                 "GO:0006397", "GO:0030900", "GO:0008380"))

data <- bind_rows(subset1, subset2) %>%
  dplyr::filter(ID %in% GOlist)

descOrder <- sort(unique(data$Description))[c(4, 10, 2, 1, 3, 11, 7, 8, 6, 5, 9)]
pValueLogMax <- 10
data <- data %>% dplyr::rowwise() %>% dplyr::mutate(pValueLog = min(-log10(p.adjust), pValueLogMax))
p <- ggplot(data, aes(x = group, y = factor(Description, levels = descOrder), size = pValueLog, fill = GeneRatio)) + 
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM) + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      # limits = c(0, 1),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL) +
  theme_bw() +  # Apply theme_bw first, so custom theme settings come after
  theme(
    panel.background = element_rect(fill = "transparent"),  # Override theme_bw panel
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      size = fontSizeS,         # Ensure size is set for x-axis text
      family = fontType,
      color = "#000000",
    ),
    axis.text.y = element_text(
      size = fontSizeS,         # Ensure size is set for y-axis text
      family = fontType,
      color = "#000000",
      lineheight = 0.9          # Allows wrapping for y-axis labels to fit into 2 lines
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )
  


fileName <- here(figDir, "..", "GO", "GO_groups_binaryGrouping")
width <- panelSize(2.5)*mmToInch
height <- panelSize(1.2)*mmToInch
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
- Average loop size
# Checking average distance of loops per gene
# temp is a tibble where delta loop and log2fc are merged
temp$group <- factor(temp$group)

temp <- temp %>% dplyr::filter(group %in% c(1, 2))


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$mean_distance
  distance2 <- (data %>% dplyr::filter(group ==group2) )$mean_distance
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pv12 <- round(getPvalWilcox(temp, 1, 2), 5)



p <- ggplot(temp, aes(x = group, y = mean_distance)) + geom_violin(aes(fill = group), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + scale_y_continuous(labels = label_kb_mb) +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")+
  annotate("text", x = 1, y = 1000000, label = paste0("pv12: ", pv12),
           color = "black", hjust = 0, size = 3)
  
  
fileName <- paste0("size_barplot_diffGroup_dTAG_vs_DMSO_binaryGroup")
height <- 3
width <- 2
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-N
# Counting number of loop per genes
tempSum <- geneAnnoData %>% dplyr::select(peakID, gene, Anno2) %>% unnest(gene) %>% group_by(gene) %>%  summarize(
    peak = list(peakID),
    anno2 = list(Anno2),
    count = n())

tempSum <- tempSum %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2", NA))
) %>% dplyr::filter(!is.na(group)) %>% dplyr::filter(group %in% c("group1", "group2"))

# 
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$count
  distance2 <- (data %>% dplyr::filter(group ==group2) )$count
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


pv12 <- round(getPvalWilcox(tempSum,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(tempSum,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(tempSum,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(tempSum,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(tempSum,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(tempSum,"group5", "group8"), 5)


p <- ggplot(tempSum, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA, color = "black", alpha = 0.6,
                 linewidth = lineThick * mmToLineUnit, lineend = "square", show.legend = FALSE) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2)) + 
  labs(x = NULL, y = "# of P-N loops per gene") +
  coord_cartesian(ylim = c(0, 8)) +
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  )+
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", convPvalue(pv12)),
           color = "black", hjust = 0, size = 1) +
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_binaryGroup")
width <- panelSize(0.8)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Counting loop types
#######
temp2 <- tempSum %>% rowwise() %>% mutate(total = length(anno2),
                                 num_pp = sum(anno2 == "P-P"),
                                 num_pe = sum(anno2 == "P-E"),
                                 num_ps = sum(anno2 == "P-S"),
                                 num_px = sum(anno2 == "P-X"),
                                 ratio_reg = (num_pp + num_pe)/total,
                                 ratio_str = num_ps/total)

#saveRDS(temp2, here(resultDir, "gene_loop_link_A485.rds"))


loopType <- temp2 %>% group_by(group) %>% summarise(num_pp = sum(num_pp),
                                        num_pe = sum(num_pe),
                                        num_ps = sum(num_ps),
                                        num_px = sum(num_px))


loopTypeLong <- loopType %>% pivot_longer(-group, names_to = "type", values_to = "count")

loopTypeLong$type <- factor(loopTypeLong$type, levels = c("num_pp", "num_pe", "num_ps", "num_px"))

# Plotting
ggplot(loopTypeLong, aes(fill=type, y=count, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()
- Loop number per gene: P-P
########
#P-P
data <- temp2 %>% dplyr::select(group, num_pp)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)


p <- ggplot(data, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA, color = "black", alpha = 0.6,
                 linewidth = lineThick * mmToLineUnit, lineend = "square", show.legend = FALSE) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2)) + 
  labs(x = NULL, y = "# of P-P loops per gene") +
  coord_cartesian(ylim = c(0, 4)) +
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  )+
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", convPvalue(pv12)),
           color = "black", hjust = 0, size = 1) +
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )

fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_pp_binaryGroup")
width <- panelSize(0.8)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-E
########
#P-E
data <- temp2 %>% dplyr::select(group, num_pe)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)


p <- ggplot(data, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA, color = "black", alpha = 0.6,
                 linewidth = lineThick * mmToLineUnit, lineend = "square", show.legend = FALSE) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2)) + 
  labs(x = NULL, y = "# of P-E loops per gene") +
  coord_cartesian(ylim = c(0, 4)) +
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  )+
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", convPvalue(pv12)),
           color = "black", hjust = 0, size = 1) +
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )



fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_pe_binaryGroup")
width <- panelSize(0.8)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-S
########
#P-S
data <- temp2 %>% dplyr::select(group, num_ps)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)


p <- ggplot(data, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA, color = "black", alpha = 0.6,
                 linewidth = lineThick * mmToLineUnit, lineend = "square", show.legend = FALSE) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2)) + 
  labs(x = NULL, y = "# of P-S loops per gene") +
  coord_cartesian(ylim = c(0, 4)) +
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  )+
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", convPvalue(pv12)),
           color = "black", hjust = 0, size = 1) +
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )



fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_ps_binaryGroup")
width <- panelSize(0.8)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

dTAG

- Splitting genes to groups
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


fcCutoff <- 0.5
diffCutoff <- 0.2
# 
temp <- temp %>%
  dplyr::mutate(group = ifelse(mean_diff_score < -diffCutoff,
                               ifelse(shrinked_log2FC < -fcCutoff, 1,
                                      ifelse(shrinked_log2FC <fcCutoff, 2, 3)),
                               ifelse(mean_diff_score < diffCutoff,
                                      ifelse(shrinked_log2FC < -fcCutoff, 4,
                                             ifelse(shrinked_log2FC < fcCutoff, 5, 6)),
                                      ifelse(shrinked_log2FC < -fcCutoff, 7,
                                             ifelse(shrinked_log2FC < fcCutoff, 8, 9)))))


gene.group1 <- (temp %>% dplyr::filter(group == 1))$gene
gene.group2 <- (temp %>% dplyr::filter(group == 2))$gene
gene.group3 <- (temp %>% dplyr::filter(group == 3))$gene
gene.group4 <- (temp %>% dplyr::filter(group == 4))$gene
gene.group5 <- (temp %>% dplyr::filter(group == 5))$gene
gene.group6 <- (temp %>% dplyr::filter(group == 6))$gene
gene.group7 <- (temp %>% dplyr::filter(group == 7))$gene
gene.group8 <- (temp %>% dplyr::filter(group == 8))$gene
gene.group9 <- (temp %>% dplyr::filter(group == 9))$gene

fwrite((temp %>% dplyr::filter(group == 1)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 2)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 3)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group3.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 4)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group4.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 5)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 6)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group6.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 7)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group7.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 8)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 9)), here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group9.tsv"), sep = "\t")


# Adding group information to geneAnno
geneAnnoData <- geneAnnoData %>% unnest(gene) %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2",
                        ifelse(gene %in% gene.group3, "group3",
                               ifelse(gene %in% gene.group4, "group4",
                                      ifelse(gene %in% gene.group5, "group5",
                                             ifelse(gene %in% gene.group6, "group6",
                                                    ifelse(gene %in% gene.group7, "group7",
                                                           ifelse(gene %in% gene.group8, "group8",
                                                                  ifelse(gene %in% gene.group9, "group9", NA)))))))))
)
- GO for each group
GO1 <- enrichGO(gene = gene.group1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO2 <- enrichGO(gene = gene.group2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO5 <- enrichGO(gene = gene.group5, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO8 <- enrichGO(gene = gene.group8, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")

GO1.df <- as.data.frame(GO1)
GO2.df <- as.data.frame(GO2)
GO3.df <- as.data.frame(GO5)
GO4.df <- as.data.frame(GO8)

subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "group1") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset2 <- GO2.df %>% dplyr::select(ID, Description,GeneRatio, p.adjust) %>% dplyr::mutate(group = "group2") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset3 <- GO3.df %>% dplyr::select(ID, Description,GeneRatio, p.adjust) %>% dplyr::mutate(group = "group3") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))

GOlist <- factor(c("GO:0033002", "GO:0070373", "GO:0048730", "GO:0031103",
                 "GO:0022613", "GO:0050767", "GO:0034470", "GO:0016055", 
                 "GO:0006397", "GO:0030900", "GO:0008380"))

data <- bind_rows(bind_rows(subset1, subset2), subset3) %>%
  dplyr::filter(ID %in% GOlist)

descOrder <- sort(unique(data$Description))[c(1, 2, 5, 7,
                                 3, 4, 6, 8, 9, 10, 11)]

p <- ggplot(data, aes(x = group, y = factor(Description, level = descOrder), color = p.adjust, size = gr)) + 
  geom_point() + theme_bw() +
  scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
  scale_size_continuous(range = c(0, 3)) +
  labs(x = NULL, y = NULL) +
  theme(axis.text = element_text(size = 6),  # Set axis text size
        axis.title = element_text(size = 6), # Set axis title size (if not removed)
        legend.text = element_text(size = 6), # Set legend text size
        legend.title = element_text(size = 6)) 

fileName <- here(figDir, "..", "GO", "GO_groups")
height = 2
width = 3.5
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
- Average loop size
# Checking average distance of loops per gene
# temp is a tibble where delta loop and log2fc are merged
temp$group <- factor(temp$group)

#
temp <- temp %>% dplyr::filter(group %in% c(1, 2, 5, 8))


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$mean_distance
  distance2 <- (data %>% dplyr::filter(group ==group2) )$mean_distance
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pv12 <- round(getPvalWilcox(temp, 1, 2), 5)
pv15 <- round(getPvalWilcox(temp, 1, 5), 5)
pv18 <- round(getPvalWilcox(temp, 1, 8), 5)
pv25 <- round(getPvalWilcox(temp, 2, 5), 5)
pv28 <- round(getPvalWilcox(temp, 2, 8), 5)
pv58 <- round(getPvalWilcox(temp, 5, 8), 5)


p <- ggplot(temp, aes(x = group, y = mean_distance)) + geom_violin(aes(fill = group), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + scale_y_continuous(labels = label_kb_mb) +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  annotate("text", x = 1, y = 1000000, label = paste0("pv12: ", pv12, "\n",
                                                      "pv15: ", pv15, "\n",
                                                      "pv18: ", pv18, "\n",
                                                      "pv25: ", pv25, "\n",
                                                      "pv28: ", pv28, "\n",
                                                      "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 3)
  
  
fileName <- paste0("size_barplot_diffGroup_dTAG_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-N
# Counting number of loop per genes
tempSum <- geneAnnoData %>% dplyr::select(peakID, gene, Anno2) %>% unnest(gene) %>% group_by(gene) %>%  summarize(
    peak = list(peakID),
    anno2 = list(Anno2),
    count = n())

tempSum <- tempSum %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2",
                        ifelse(gene %in% gene.group3, "group3",
                               ifelse(gene %in% gene.group4, "group4",
                                      ifelse(gene %in% gene.group5, "group5",
                                             ifelse(gene %in% gene.group6, "group6",
                                                    ifelse(gene %in% gene.group7, "group7",
                                                           ifelse(gene %in% gene.group8, "group8",
                                                                  ifelse(gene %in% gene.group9, "group9", NA)))))))))
) %>%
  dplyr::filter(group %in% c("group1", "group2", "group5", "group8"))


# TEMP START
#geneList.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))
#geneList.group1.temp <- geneList.group1 %>% dplyr::left_join(tempSum, by = c("gene"))
# TEMP END

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$count
  distance2 <- (data %>% dplyr::filter(group ==group2) )$count
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


pv12 <- round(getPvalWilcox(tempSum,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(tempSum,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(tempSum,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(tempSum,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(tempSum,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(tempSum,"group5", "group8"), 5)


p <- ggplot(tempSum, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2), limits = c(0, 10)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1) +  theme(legend.position = "none")


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Counting loop types
#######
temp2 <- tempSum %>% rowwise() %>% mutate(total = length(anno2),
                                 num_pp = sum(anno2 == "P-P"),
                                 num_pe = sum(anno2 == "P-E"),
                                 num_ps = sum(anno2 == "P-S"),
                                 num_px = sum(anno2 == "P-X"),
                                 ratio_reg = (num_pp + num_pe)/total,
                                 ratio_str = num_ps/total)

saveRDS(temp2, here(resultDir, "gene_loop_link.rds"))


loopType <- temp2 %>% group_by(group) %>% summarise(num_pp = sum(num_pp),
                                        num_pe = sum(num_pe),
                                        num_ps = sum(num_ps),
                                        num_px = sum(num_px))


loopTypeLong <- loopType %>% pivot_longer(-group, names_to = "type", values_to = "count")

loopTypeLong$type <- factor(loopTypeLong$type, levels = c("num_pp", "num_pe", "num_ps", "num_px"))

# Plotting
ggplot(loopTypeLong, aes(fill=type, y=count, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()
- Loop number per gene: P-P
########
#P-P
data <- temp2 %>% dplyr::select(group, num_pp)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1)+  theme(legend.position = "none")


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_pp")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-E
########
#P-E
data <- temp2 %>% dplyr::select(group, num_pe)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1)+  theme(legend.position = "none")


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_pe")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-S
########
#P-S
data <- temp2 %>% dplyr::select(group, num_ps)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1)+  theme(legend.position = "none")


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_ps")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-X
########
#P-X
data <- temp2 %>% dplyr::select(group, num_px)
colnames(data) <- c("group", "count")
pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1)+  theme(legend.position = "none")


fileName <- paste0("count_barplot_diffGroup_dTAG_vs_DMSO_px")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

A485

- Splitting genes to groups
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)


temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


fcCutoff <- 0.5
diffCutoff <- 0.2
# 
temp <- temp %>%
  dplyr::mutate(group = ifelse(mean_diff_score < -diffCutoff,
                               ifelse(shrinked_log2FC < -fcCutoff, 1,
                                      ifelse(shrinked_log2FC <fcCutoff, 2, 3)),
                               ifelse(mean_diff_score < diffCutoff,
                                      ifelse(shrinked_log2FC < -fcCutoff, 4,
                                             ifelse(shrinked_log2FC < fcCutoff, 5, 6)),
                                      ifelse(shrinked_log2FC < -fcCutoff, 7,
                                             ifelse(shrinked_log2FC < fcCutoff, 8, 9)))))


gene.group1 <- (temp %>% dplyr::filter(group == 1))$gene
gene.group2 <- (temp %>% dplyr::filter(group == 2))$gene
gene.group3 <- (temp %>% dplyr::filter(group == 3))$gene
gene.group4 <- (temp %>% dplyr::filter(group == 4))$gene
gene.group5 <- (temp %>% dplyr::filter(group == 5))$gene
gene.group6 <- (temp %>% dplyr::filter(group == 6))$gene
gene.group7 <- (temp %>% dplyr::filter(group == 7))$gene
gene.group8 <- (temp %>% dplyr::filter(group == 8))$gene
gene.group9 <- (temp %>% dplyr::filter(group == 9))$gene

fwrite((temp %>% dplyr::filter(group == 1)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group1.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 2)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group2.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 3)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group3.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 4)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group4.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 5)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group5.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 6)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group6.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 7)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group7.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 8)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group8.tsv"), sep = "\t")
fwrite((temp %>% dplyr::filter(group == 9)), here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group9.tsv"), sep = "\t")


# Adding group information to geneAnno
geneAnnoData <- geneAnnoData %>% unnest(gene) %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2",
                        ifelse(gene %in% gene.group3, "group3",
                               ifelse(gene %in% gene.group4, "group4",
                                      ifelse(gene %in% gene.group5, "group5",
                                             ifelse(gene %in% gene.group6, "group6",
                                                    ifelse(gene %in% gene.group7, "group7",
                                                           ifelse(gene %in% gene.group8, "group8",
                                                                  ifelse(gene %in% gene.group9, "group9", NA)))))))))
)
- GO for each group
GO1 <- enrichGO(gene = gene.group1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO2 <- enrichGO(gene = gene.group2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO3 <- enrichGO(gene = gene.group3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO4 <- enrichGO(gene = gene.group4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO5 <- enrichGO(gene = gene.group5, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO6 <- enrichGO(gene = gene.group6, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO7 <- enrichGO(gene = gene.group7, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO8 <- enrichGO(gene = gene.group8, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO9 <- enrichGO(gene = gene.group9, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")

dotplot(GO1, showCategory = 10)

# 
# GO1.df <- as.data.frame(GO1)
# GO2.df <- as.data.frame(GO2)
# GO3.df <- as.data.frame(GO5)
# GO4.df <- as.data.frame(GO8)
# 
# subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "group1") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset2 <- GO2.df %>% dplyr::select(ID, Description,GeneRatio, p.adjust) %>% dplyr::mutate(group = "group2") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset3 <- GO3.df %>% dplyr::select(ID, Description,GeneRatio, p.adjust) %>% dplyr::mutate(group = "group3") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# 
# GOlist <- factor(c("GO:0033002", "GO:0070373", "GO:0048730", "GO:0031103",
#                  "GO:0022613", "GO:0050767", "GO:0034470", "GO:0016055", 
#                  "GO:0006397", "GO:0030900", "GO:0008380"))
# 
# data <- bind_rows(bind_rows(subset1, subset2), subset3) %>%
#   dplyr::filter(ID %in% GOlist)
# 
# descOrder <- sort(unique(data$Description))[c(1, 2, 5, 7,
#                                  3, 4, 6, 8, 9, 10, 11)]
# 
# p <- ggplot(data, aes(x = group, y = factor(Description, level = descOrder), color = p.adjust, size = gr)) + 
#   geom_point() + theme_bw() +
#   scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
#   scale_size_continuous(range = c(0, 3)) +
#   labs(x = NULL, y = NULL) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- here(figDir, "..", "GO", "GO_groups")
# height = 2
# width = 3.5
# svglite(paste0(fileName, ".svg"), height = height, width = width)
# print(p)
# dev.off()
- Average loop size
# Checking average distance of loops per gene
# temp is a tibble where delta loop and log2fc are merged
temp$group <- factor(temp$group)


# 
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(group ==group1) )$mean_distance
#   distance2 <- (data %>% dplyr::filter(group ==group2) )$mean_distance
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# pv12 <- round(getPvalWilcox(temp, 1, 2), 5)
# pv15 <- round(getPvalWilcox(temp, 1, 5), 5)
# pv18 <- round(getPvalWilcox(temp, 1, 8), 5)
# pv25 <- round(getPvalWilcox(temp, 2, 5), 5)
# pv28 <- round(getPvalWilcox(temp, 2, 8), 5)
# pv58 <- round(getPvalWilcox(temp, 5, 8), 5)


p <- ggplot(temp, aes(x = group, y = mean_distance)) + geom_violin(aes(fill = group), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + scale_y_continuous(labels = label_kb_mb) +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")
  # annotate("text", x = 1, y = 1000000, label = paste0("pv12: ", pv12, "\n",
  #                                                     "pv15: ", pv15, "\n",
  #                                                     "pv18: ", pv18, "\n",
  #                                                     "pv25: ", pv25, "\n",
  #                                                     "pv28: ", pv28, "\n",
  #                                                     "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 3)
  # 
  
fileName <- paste0("size_barplot_diffGroup_A485_vs_DMSO")
height <- 3
width <- 4
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-N
# Counting number of loop per genes
tempSum <- geneAnnoData %>% dplyr::select(peakID, gene, Anno2) %>% unnest(gene) %>% group_by(gene) %>%  summarize(
    peak = list(peakID),
    anno2 = list(Anno2),
    count = n())

tempSum <- tempSum %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2",
                        ifelse(gene %in% gene.group3, "group3",
                               ifelse(gene %in% gene.group4, "group4",
                                      ifelse(gene %in% gene.group5, "group5",
                                             ifelse(gene %in% gene.group6, "group6",
                                                    ifelse(gene %in% gene.group7, "group7",
                                                           ifelse(gene %in% gene.group8, "group8",
                                                                  ifelse(gene %in% gene.group9, "group9", NA)))))))))
) %>% dplyr::filter(!is.na(group))

# 
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(group ==group1) )$count
#   distance2 <- (data %>% dplyr::filter(group ==group2) )$count
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# 
# pv12 <- round(getPvalWilcox(tempSum,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(tempSum,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(tempSum,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(tempSum,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(tempSum,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(tempSum,"group5", "group8"), 5)


p <- ggplot(tempSum, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 10, by = 2)) + 
  coord_cartesian(ylim = c(0, 10)) +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  theme(legend.position = "none")
  # annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
  #                                               "pv15: ", pv15, "\n",
  #                                               "pv18: ", pv18, "\n",
  #                                               "pv25: ", pv25, "\n",
  #                                               "pv28: ", pv28, "\n",
  #                                               "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 1) +  


fileName <- paste0("count_barplot_diffGroup_A485_vs_DMSO")
height <- 3
width <- 4
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Counting loop types
#######
temp2 <- tempSum %>% rowwise() %>% mutate(total = length(anno2),
                                 num_pp = sum(anno2 == "P-P"),
                                 num_pe = sum(anno2 == "P-E"),
                                 num_ps = sum(anno2 == "P-S"),
                                 num_px = sum(anno2 == "P-X"),
                                 ratio_reg = (num_pp + num_pe)/total,
                                 ratio_str = num_ps/total)

saveRDS(temp2, here(resultDir, "gene_loop_link_A485.rds"))


loopType <- temp2 %>% group_by(group) %>% summarise(num_pp = sum(num_pp),
                                        num_pe = sum(num_pe),
                                        num_ps = sum(num_ps),
                                        num_px = sum(num_px))


loopTypeLong <- loopType %>% pivot_longer(-group, names_to = "type", values_to = "count")

loopTypeLong$type <- factor(loopTypeLong$type, levels = c("num_pp", "num_pe", "num_ps", "num_px"))

# Plotting
ggplot(loopTypeLong, aes(fill=type, y=count, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()
- Loop number per gene: P-P
########
#P-P
data <- temp2 %>% dplyr::select(group, num_pp)
colnames(data) <- c("group", "count")
# pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  theme(legend.position = "none")
  # annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
  #                                               "pv15: ", pv15, "\n",
  #                                               "pv18: ", pv18, "\n",
  #                                               "pv25: ", pv25, "\n",
  #                                               "pv28: ", pv28, "\n",
  #                                               "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 1)


fileName <- paste0("count_barplot_diffGroup_A485_vs_DMSO_pp")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-E
########
#P-E
data <- temp2 %>% dplyr::select(group, num_pe)
colnames(data) <- c("group", "count")
# pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  theme(legend.position = "none")
  # annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
  #                                               "pv15: ", pv15, "\n",
  #                                               "pv18: ", pv18, "\n",
  #                                               "pv25: ", pv25, "\n",
  #                                               "pv28: ", pv28, "\n",
  #                                               "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 1)


fileName <- paste0("count_barplot_diffGroup_A485_vs_DMSO_pe")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-S
########
#P-S
data <- temp2 %>% dplyr::select(group, num_ps)
colnames(data) <- c("group", "count")
# pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  theme(legend.position = "none")
  # annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
  #                                               "pv15: ", pv15, "\n",
  #                                               "pv18: ", pv18, "\n",
  #                                               "pv25: ", pv25, "\n",
  #                                               "pv28: ", pv28, "\n",
  #                                               "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 1)+  


fileName <- paste0("count_barplot_diffGroup_A485_vs_DMSO_ps")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Loop number per gene: P-X
########
#P-X
data <- temp2 %>% dplyr::select(group, num_px)
colnames(data) <- c("group", "count")
# pv12 <- round(getPvalWilcox(data,"group1", "group2"), 5)
# pv15 <- round(getPvalWilcox(data,"group1", "group5"), 5)
# pv18 <- round(getPvalWilcox(data,"group1", "group8"), 5)
# pv25 <- round(getPvalWilcox(data,"group2", "group5"), 5)
# pv28 <- round(getPvalWilcox(data,"group2", "group8"), 5)
# pv58 <- round(getPvalWilcox(data,"group5", "group8"), 5)

p <- ggplot(data, aes(x = group, y = count, fill = group)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() +       
  scale_y_continuous(breaks = seq(0, 5, by = 2), limits = c(0, 5)) + 
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  theme(legend.position = "none")
  # annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
  #                                               "pv15: ", pv15, "\n",
  #                                               "pv18: ", pv18, "\n",
  #                                               "pv25: ", pv25, "\n",
  #                                               "pv28: ", pv28, "\n",
  #                                               "pv58: ", pv58, "\n"), 
  #          color = "black", hjust = 0, size = 1)+  


fileName <- paste0("count_barplot_diffGroup_A485_vs_DMSO_px")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

dTAG

Grouping with P-N number

Grouping
name <- "chromo_cons_annoHierarchy"

alpha <- 0.05
fcCutoff <- 0.5
diff.PRO.G1.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G1.dTAG_vs_G1.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.PRO.G2.dTAG <- fread(here(refDir, "diff_G1G2.dTAG_G2.dTAG_vs_G2.DMSO_PROseq.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
############
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))



# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers
resultDir <- here("../../result")

temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))


pnOver8 <- (temp2 %>% dplyr::filter(total >= 8))$gene
pnOver6 <- (temp2 %>% dplyr::filter(total >= 6, total < 8))$gene
pnOver4 <- (temp2 %>% dplyr::filter(total >= 4, total < 6))$gene
pnOver2 <- (temp2 %>% dplyr::filter(total >= 2, total < 4))$gene
pnOver0 <- (temp2 %>% dplyr::filter(total < 2))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% diff.RNA.G1.dTAG$ensembl_gene_id, "2DOWN", "0NO"),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                log2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag) %>%
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  pnOver = ifelse(gene %in% pnOver8, "pnOver8",
                  ifelse(gene %in% pnOver6, "pnOver6",
                         ifelse(gene %in% pnOver4, "pnOver4",
                                ifelse(gene %in% pnOver2, "pnOver2",
                                       ifelse(gene %in% pnOver0, "pnOver0", NA)))))) %>%
  drop_na(pnOver)
GO for each group
GOfigDir <- here(figDir, "../GO")
getGO("pnOver8", GOfigDir, pnOver8)
getGO("pnOver6", GOfigDir, pnOver6)
getGO("pnOver4", GOfigDir, pnOver4)
getGO("pnOver2", GOfigDir, pnOver2)
getGO("pnOver0", GOfigDir, pnOver0)

#####################
GO0.df <- as.data.frame(enrichGO(gene = pnOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
GO2.df <- as.data.frame(enrichGO(gene = pnOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
GO4.df <- as.data.frame(enrichGO(gene = pnOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
GO6.df <- as.data.frame(enrichGO(gene = pnOver6, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
GO8.df <- as.data.frame(enrichGO(gene = pnOver8, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))


subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver0") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver2") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver4") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset6 <- GO6.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver6") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))
subset8 <- GO8.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver8") %>%
  dplyr::mutate(
    gr = sapply(GeneRatio, function(x) {
      # Split the string by "/"
      parts <- unlist(strsplit(x, "/"))
      # Convert to numeric and perform the division
      as.numeric(parts[1]) / as.numeric(parts[2])
    })
  ) %>% dplyr::arrange(desc(gr))


GOlist <- factor(c("GO:0006397", "GO:0008380", "GO:0022613", "GO:0034470",
                   "GO:0016055", "GO:0007389", "GO:0048562", "GO:0045165", 
                   "GO:0072001", "GO:0007517", "GO:0048705"))

data <- bind_rows(bind_rows(bind_rows(subset0, subset2), subset4), subset8) %>%
  dplyr::filter(ID %in% GOlist)

p <- ggplot(data, aes(x = group, y = Description, color = p.adjust, size = gr)) + 
  geom_point() + theme_bw() +
  scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
  scale_size_continuous(range = c(0, 3)) +
  labs(x = NULL, y = NULL) +
  theme(axis.text = element_text(size = 6),  # Set axis text size
        axis.title = element_text(size = 6), # Set axis title size (if not removed)
        legend.text = element_text(size = 6), # Set legend text size
        legend.title = element_text(size = 6)) 

fileName <- here(figDir, "..", "GO", "GO_groups_pn")
height = 2
width = 3.3
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
loop score
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(pnOver ==group1) )$mean_diff_score
  distance2 <- (data %>% dplyr::filter(pnOver ==group2) )$mean_diff_score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pv02 <- round(getPvalWilcox(temp, "pnOver0", "pnOver2"), 5)
pv24 <- round(getPvalWilcox(temp, "pnOver2", "pnOver4"), 5)
pv46 <- round(getPvalWilcox(temp, "pnOver4", "pnOver6"), 5)
pv08 <- round(getPvalWilcox(temp, "pnOver0", "pnOver8"), 5)
pv28 <- round(getPvalWilcox(temp, "pnOver2", "pnOver8"), 5)
pv48 <- round(getPvalWilcox(temp, "pnOver4", "pnOver8"), 5)
pv68 <- round(getPvalWilcox(temp, "pnOver6", "pnOver8"), 5)


p <- ggplot(temp, aes(x = pnOver, y = mean_diff_score)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0.2)+
  annotate("text", x = 1, y = 0, label = paste0("pv02: ", convPvalue(pv02), "\n",
                                                "pv24: ", convPvalue(pv24), "\n",
                                                "pv46: ", convPvalue(pv46), "\n",
                                                "pv68: ", convPvalue(pv68), "\n",
                                                "pv48: ", convPvalue(pv48), "\n",
                                                "pv28: ", convPvalue(pv28), "\n",
                                                "pv08: ", convPvalue(pv08), "\n"), 
           color = "black", hjust = 0, size = 3)

  
fileName <- paste0("diffScore_barplot_pnGroup_dTAG_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
#
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(pnOver ==group1) )$log2FoldChange
  distance2 <- (data %>% dplyr::filter(pnOver ==group2) )$log2FoldChange
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
 
pv02 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver2"), 5)
pv04 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver4"), 5)
pv06 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver6"), 5)
pv08 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver8"), 5)
pv24 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver4"), 5)
pv26 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver6"), 5)
pv28 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver8"), 5)
pv46 <- round(getPvalWilcox(tempDown, "pnOver4", "pnOver6"), 5)
pv48 <- round(getPvalWilcox(tempDown, "pnOver4", "pnOver8"), 5)
pv68 <- round(getPvalWilcox(tempDown, "pnOver6", "pnOver8"), 5)




p <- ggplot(tempDown, aes(x = pnOver, y = log2FoldChange)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)+
  annotate("text", x = 1, y = -0.5, label = paste0("pv02: ", convPvalue(pv02), "\n",
                                                   "pv04: ", convPvalue(pv04), "\n",
                                                   "pv06: ", convPvalue(pv06), "\n",
                                                   "pv08: ", convPvalue(pv08), "\n",
                                                   "pv24: ", convPvalue(pv24), "\n",
                                                   "pv26: ", convPvalue(pv26), "\n",
                                                   "pv28: ", convPvalue(pv28), "\n",
                                                   "pv46: ", convPvalue(pv46), "\n",
                                                   "pv48: ", convPvalue(pv48), "\n",
                                                   "pv68: ", convPvalue(pv68), "\n"), 
           color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(-1, 0))

  
fileName <- paste0("log2FC_barplot_pnGroup_dTAG_vs_DMSO_down")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
 
pv02 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver2"), 5)
pv04 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver4"), 5)
pv06 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver6"), 5)
pv08 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver8"), 5)
pv24 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver4"), 5)
pv26 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver6"), 5)
pv28 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver8"), 5)
pv46 <- round(getPvalWilcox(tempUp, "pnOver4", "pnOver6"), 5)
pv48 <- round(getPvalWilcox(tempUp, "pnOver4", "pnOver8"), 5)
pv68 <- round(getPvalWilcox(tempUp, "pnOver6", "pnOver8"), 5)




p <- ggplot(tempUp, aes(x = pnOver, y = log2FoldChange)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)+
  annotate("text", x = 1, y = 0.5, label = paste0("pv02: ", convPvalue(pv02), "\n",
                                                   "pv04: ", convPvalue(pv04), "\n",
                                                   "pv06: ", convPvalue(pv06), "\n",
                                                   "pv08: ", convPvalue(pv08), "\n",
                                                   "pv24: ", convPvalue(pv24), "\n",
                                                   "pv26: ", convPvalue(pv26), "\n",
                                                   "pv28: ", convPvalue(pv28), "\n",
                                                   "pv46: ", convPvalue(pv46), "\n",
                                                   "pv48: ", convPvalue(pv48), "\n",
                                                   "pv68: ", convPvalue(pv68), "\n"), 
           color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_pnGroup_dTAG_vs_DMSO_up")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-S number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% diff.RNA.G1.dTAG$ensembl_gene_id, "2DOWN", "0NO"),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                log2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag) %>%
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  psOver = ifelse(gene %in% psOver4, "psOver4",
                  ifelse(gene %in% psOver3, "psOver3",
                         ifelse(gene %in% psOver2, "psOver2",
                                ifelse(gene %in% psOver1, "psOver1",
                                       ifelse(gene %in% psOver0, "psOver0", NA)))))) %>%
  drop_na(psOver)
GO for each group
GOfigDir <- here(figDir, "../GO")

#####################
GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))

fwrite(GO0.df, here("GO_PS_group0.tsv"), sep = "\t")
fwrite(GO1.df, here("GO_PS_group1.tsv"), sep = "\t")
fwrite(GO2.df, here("GO_PS_group2.tsv"), sep = "\t")
fwrite(GO3.df, here("GO_PS_group3.tsv"), sep = "\t")
fwrite(GO4.df, here("GO_PS_group4.tsv"), sep = "\t")

GO0.df <- fread(here("GO_PS_group0.tsv"))
GO1.df <- fread(here("GO_PS_group1.tsv"))
GO2.df <- fread(here("GO_PS_group2.tsv"))
GO3.df <- fread(here("GO_PS_group3.tsv"))
GO4.df <- fread(here("GO_PS_group4.tsv"))

subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 0") %>%
  dplyr::arrange(p.adjust)
subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 1") %>%
  dplyr::arrange(p.adjust)
subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 2") %>%
  dplyr::arrange(p.adjust)
subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 3") %>%
  dplyr::arrange(p.adjust)
subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 4") %>%
  dplyr::arrange(p.adjust)

subset0$GeneRatio <- sapply(strsplit(subset0$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset1$GeneRatio <- sapply(strsplit(subset1$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset2$GeneRatio <- sapply(strsplit(subset2$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset3$GeneRatio <- sapply(strsplit(subset3$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset4$GeneRatio <- sapply(strsplit(subset4$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))


GOlist <- factor(c("GO:0008380", "GO:0006397", "GO:0034470", "GO:0022613", "GO:0016055",
                   "GO:0061138", "GO:0060562", "GO:0007389", "GO:0060485", "GO:0048638", "GO:0045664"))

data <- bind_rows(bind_rows(bind_rows(bind_rows(subset0, subset1), subset2), subset3), subset4) %>%
  dplyr::filter(ID %in% GOlist)

descOrder <- sort(unique(data$Description))[rev(c(10, 4, 5, 9, 11,
                                                  2, 6,
                                                  3, 1, 8, 7))]

data <- data %>% dplyr::rowwise() %>% dplyr::mutate(pValueLog = min(-log10(p.adjust), pValueLogMax))
p <- ggplot(data, aes(x = group, y = factor(Description, levels = descOrder), size = pValueLog, fill = GeneRatio)) + 
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM) + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      # limits = c(0, 1),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL) +
  theme_bw() +  # Apply theme_bw first, so custom theme settings come after
  theme(
    panel.background = element_rect(fill = "transparent"),  # Override theme_bw panel
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      size = fontSizeS,         # Ensure size is set for x-axis text
      family = fontType,
      color = "#000000",
    ),
    axis.text.y = element_text(
      size = fontSizeS,         # Ensure size is set for y-axis text
      family = fontType,
      color = "#000000",
      lineheight = 0.9          # Allows wrapping for y-axis labels to fit into 2 lines
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "..", "GO", "GO_groups_ps")
width <- panelSize(2.7)*mmToInch
height <- panelSize(1.2)*mmToInch
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
loop score
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)


p <- ggplot(temp, aes(x = psOver, y = mean_diff_score)) + 
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineMedium * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "Average Δ loop score") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) +
    scale_fill_manual(values = c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C")) +
  coord_cartesian(ylim = c(-0.5, 0.1))



fileName <- paste0("diffScore_barplot_psGroup_dTAG_vs_DMSO_2")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
temp <- temp %>% dplyr::mutate(absLog2FC = abs(log2FoldChange))

ks_result1 <- ks.test(
  temp %>% dplyr::filter(psOver == "psOver4") %>% pull(absLog2FC),
  temp %>% dplyr::filter(psOver == "psOver3") %>% pull(absLog2FC)
)
ks_result2 <- ks.test(
  temp %>% dplyr::filter(psOver == "psOver4") %>% pull(absLog2FC),
  temp %>% dplyr::filter(psOver == "psOver2") %>% pull(absLog2FC)
)
ks_result3 <- ks.test(
  temp %>% dplyr::filter(psOver == "psOver4") %>% pull(absLog2FC),
  temp %>% dplyr::filter(psOver == "psOver1") %>% pull(absLog2FC)
)
ks_result4 <- ks.test(
  temp %>% dplyr::filter(psOver == "psOver4") %>% pull(absLog2FC),
  temp %>% dplyr::filter(psOver == "psOver0") %>% pull(absLog2FC)
)

p <- ggplot(temp, aes(x = absLog2FC, color = psOver)) +
scale_color_manual(values = (c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))) +
  stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square" ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    ) + scale_y_continuous(labels = scales::number_format(accuracy = 0.1))
fileName <- paste0("log2FC_cdf_psGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()




#
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
 
ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)

ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)


p <- ggplot(tempDown, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(-1, 0))
  
fileName <- paste0("log2FC_barplot_psGroup_dTAG_vs_DMSO_down")
width <- panelSize(1.2)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
 
ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)




p <- ggplot(tempUp, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_psGroup_dTAG_vs_DMSO_up")
width <- panelSize(1.18)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-E number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers

psOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% diff.RNA.G1.dTAG$ensembl_gene_id, "2DOWN", "0NO"),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                log2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag) %>%
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  psOver = ifelse(gene %in% psOver4, "psOver4",
                  ifelse(gene %in% psOver3, "psOver3",
                         ifelse(gene %in% psOver2, "psOver2",
                                ifelse(gene %in% psOver1, "psOver1",
                                       ifelse(gene %in% psOver0, "psOver0", NA)))))) %>%
  drop_na(psOver)
GO for each group
GOfigDir <- here(figDir, "../GO")
#####################
GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))

# fwrite(GO0.df, here("GO_PE_group0.tsv"), sep = "\t")
# fwrite(GO1.df, here("GO_PE_group1.tsv"), sep = "\t")
# fwrite(GO2.df, here("GO_PE_group2.tsv"), sep = "\t")
# fwrite(GO3.df, here("GO_PE_group3.tsv"), sep = "\t")
# fwrite(GO4.df, here("GO_PE_group4.tsv"), sep = "\t")


subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 0") %>%
  dplyr::arrange(p.adjust)
subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 1") %>%
  dplyr::arrange(p.adjust)
subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 2") %>%
  dplyr::arrange(p.adjust)
subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 3") %>%
  dplyr::arrange(p.adjust)
subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 4") %>%
  dplyr::arrange(p.adjust)

subset0$GeneRatio <- sapply(strsplit(subset0$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset1$GeneRatio <- sapply(strsplit(subset1$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset2$GeneRatio <- sapply(strsplit(subset2$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset3$GeneRatio <- sapply(strsplit(subset3$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset4$GeneRatio <- sapply(strsplit(subset4$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))

GOlist <- factor(c("GO:0008380", "GO:0006397", "GO:0034470", "GO:0022613", "GO:0016055",
                   "GO:0061138", "GO:0060562", "GO:0007389", "GO:0060485", "GO:0048638", "GO:0045664",
                   "GO:0040029"))

data <- bind_rows(bind_rows(bind_rows(subset0, subset1), subset2), subset4) %>%
  dplyr::filter(ID %in% GOlist)

descOrder <- sort(unique(data$Description))[rev(c(11, 5, 6, 10, 12,
                                                  1,
                                                  3, 7, 4, 2, 9, 8))]

empty_row3 <- data.frame(
  ID = NA,                             # No specific ID
  Description = NA,                    # No description
  GeneRatio = NA,                      # No gene ratio
  p.adjust = NA,                       # No p.adjust value
  group = "Group 3"                   # Group to add as empty column
)

empty_row4 <- data.frame(
  ID = NA,                             # No specific ID
  Description = NA,                    # No description
  GeneRatio = NA,                      # No gene ratio
  p.adjust = NA,                       # No p.adjust value
  group = "Group 4"                   # Group to add as empty column
)

# Append the empty row to your dataset
data <- rbind(data, empty_row3, empty_row4)


data <- data %>% dplyr::rowwise() %>% dplyr::mutate(pValueLog = min(-log10(p.adjust), pValueLogMax))
p <- ggplot(data, aes(x = group, y = factor(Description, levels = descOrder), size = pValueLog, fill = GeneRatio)) + 
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM) + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      # limits = c(0, 1),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL) +
  theme_bw() +  # Apply theme_bw first, so custom theme settings come after
  theme(
    panel.background = element_rect(fill = "transparent"),  # Override theme_bw panel
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      size = fontSizeS,         # Ensure size is set for x-axis text
      family = fontType,
      color = "#000000",
    ),
    axis.text.y = element_text(
      size = fontSizeS,         # Ensure size is set for y-axis text
      family = fontType,
      color = "#000000",
      lineheight = 0.9          # Allows wrapping for y-axis labels to fit into 2 lines
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "..", "GO", "GO_groups_pe")
width <- panelSize(2.65)*mmToInch
height <- panelSize(1.3)*mmToInch
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
loop score
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)


p <- ggplot(temp, aes(x = psOver, y = mean_diff_score)) + 
    scale_fill_manual(values = c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C")) +
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineMedium * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "Average Δ loop score") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) +
  coord_cartesian(ylim = c(-0.5, 0.1))


fileName <- paste0("diffScore_barplot_peGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
temp <- temp %>% dplyr::mutate(absLog2FC = abs(log2FoldChange))
p <- ggplot(temp, aes(x = absLog2FC, color = psOver)) +
scale_color_manual(values = (c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))) +
  stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square" ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    ) + scale_y_continuous(labels = scales::number_format(accuracy = 0.1))
fileName <- paste0("log2FC_cdf_peGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


#
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
 
ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)

ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)


p <- ggplot(tempDown, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(-1, 0))
  
fileName <- paste0("log2FC_barplot_peGroup_dTAG_vs_DMSO_down")
width <- panelSize(1.2)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
 
ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)




p <- ggplot(tempUp, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_peGroup_dTAG_vs_DMSO_up")
width <- panelSize(1.18)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-P number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers

psOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% diff.RNA.G1.dTAG$ensembl_gene_id, "2DOWN", "0NO"),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                log2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag) %>%
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  psOver = ifelse(gene %in% psOver4, "psOver4",
                  ifelse(gene %in% psOver3, "psOver3",
                         ifelse(gene %in% psOver2, "psOver2",
                                ifelse(gene %in% psOver1, "psOver1",
                                       ifelse(gene %in% psOver0, "psOver0", NA)))))) %>%
  drop_na(psOver)
GO for each group
GOfigDir <- here(figDir, "../GO")

#####################
GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP", readable = TRUE))
# 
# fwrite(GO0.df, here("GO_PP_group0.tsv"), sep = "\t")
# fwrite(GO1.df, here("GO_PP_group1.tsv"), sep = "\t")
# fwrite(GO2.df, here("GO_PP_group2.tsv"), sep = "\t")
# fwrite(GO3.df, here("GO_PP_group3.tsv"), sep = "\t")
# fwrite(GO4.df, here("GO_PP_group4.tsv"), sep = "\t")

subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 0") %>%
  dplyr::arrange(p.adjust)
subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 1") %>%
  dplyr::arrange(p.adjust)
subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 2") %>%
  dplyr::arrange(p.adjust)
subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 3") %>%
  dplyr::arrange(p.adjust)
subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "Group 4") %>%
  dplyr::arrange(p.adjust)

subset0$GeneRatio <- sapply(strsplit(subset0$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset1$GeneRatio <- sapply(strsplit(subset1$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset2$GeneRatio <- sapply(strsplit(subset2$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset3$GeneRatio <- sapply(strsplit(subset3$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
subset4$GeneRatio <- sapply(strsplit(subset4$GeneRatio, "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))

GOlist <- factor(c("GO:0008380", "GO:0006397", "GO:0034470", "GO:0022613", "GO:0016055",
                   "GO:0061138", "GO:0060562", "GO:0007389", "GO:0060485", "GO:0048638", "GO:0045664"))

data <- bind_rows(subset0, subset1) %>%
  dplyr::filter(ID %in% GOlist)



empty_row2 <- data.frame(
  ID = NA,                             # No specific ID
  Description = NA,                    # No description
  GeneRatio = NA,                      # No gene ratio
  p.adjust = NA,                       # No p.adjust value
  group = "Group 2"                   # Group to add as empty column
)

empty_row3 <- data.frame(
  ID = NA,                             # No specific ID
  Description = NA,                    # No description
  GeneRatio = NA,                      # No gene ratio
  p.adjust = NA,                       # No p.adjust value
  group = "Group 3"                   # Group to add as empty column
)

empty_row4 <- data.frame(
  ID = NA,                             # No specific ID
  Description = NA,                    # No description
  GeneRatio = NA,                      # No gene ratio
  p.adjust = NA,                       # No p.adjust value
  group = "Group 4"                   # Group to add as empty column
)

# Append the empty row to your dataset
data <- rbind(data, empty_row2, empty_row3, empty_row4)
descOrder <- sort(unique(data$Description))[rev(c(12,
                                                  4, 5, 9, 11, 10, 
                                                  2, 6, 3, 1, 8, 7))]
data <- data %>% dplyr::filter(Description %in% descOrder)


data <- data %>% dplyr::rowwise() %>% dplyr::mutate(pValueLog = min(-log10(p.adjust), pValueLogMax))
p <- ggplot(data, aes(x = group, y = factor(Description, levels = descOrder), size = pValueLog, fill = GeneRatio)) + 
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM) + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      # limits = c(0, 1),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL) +
  theme_bw() +  # Apply theme_bw first, so custom theme settings come after
  theme(
    panel.background = element_rect(fill = "transparent"),  # Override theme_bw panel
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      size = fontSizeS,         # Ensure size is set for x-axis text
      family = fontType,
      color = "#000000",
    ),
    axis.text.y = element_text(
      size = fontSizeS,         # Ensure size is set for y-axis text
      family = fontType,
      color = "#000000",
      lineheight = 0.9          # Allows wrapping for y-axis labels to fit into 2 lines
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick * mmToLineUnit,
      lineend = "square"
    ),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "..", "GO", "GO_groups_pp")
width <- panelSize(2.65)*mmToInch
height <- panelSize(1.2)*mmToInch
svglite(paste0(fileName, ".svg"), height = height, width = width)
print(p)
dev.off()
loop score
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)

p <- ggplot(temp, aes(x = psOver, y = mean_diff_score)) + 
    scale_fill_manual(values = rev(c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))) +
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineMedium * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "Average Δ loop score") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) +
  coord_cartesian(ylim = c(-0.5, 0.1))


fileName <- paste0("diffScore_barplot_ppGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
temp <- temp %>% dplyr::mutate(absLog2FC = abs(log2FoldChange))
p <- ggplot(temp, aes(x = absLog2FC, color = psOver)) +
scale_color_manual(values = (rev(c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C")))) +
  stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square" ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    ) + scale_y_continuous(labels = scales::number_format(accuracy = 0.1))
fileName <- paste0("log2FC_cdf_ppGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



#
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
  distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
 
ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)

ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)


p <- ggplot(tempDown, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(-1, 0))
  
fileName <- paste0("log2FC_barplot_ppGroup_dTAG_vs_DMSO_down")
width <- panelSize(1.2)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
 
ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)




p <- ggplot(tempUp, aes(x = psOver, y = log2FoldChange)) + 
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) + # Five shades of grey
  geom_violin(aes(fill = psOver), 
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "log2(fold change)") +
  stat_summary(
    aes(group = psOver), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_ppGroup_dTAG_vs_DMSO_up")
width <- panelSize(1.18)*mmToInch
height <- panelSize(1)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

A485

Grouping with P-N number

Grouping
############
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))


# temp2
#calculating diff score and log2fc distribution based on p-n numbers
temp2 <- readRDS(here(resultDir, "gene_loop_link_A485.rds"))

pnOver8 <- (temp2 %>% dplyr::filter(total >= 8))$gene
pnOver6 <- (temp2 %>% dplyr::filter(total >= 6, total < 8))$gene
pnOver4 <- (temp2 %>% dplyr::filter(total >= 4, total < 6))$gene
pnOver2 <- (temp2 %>% dplyr::filter(total >= 2, total < 4))$gene
pnOver0 <- (temp2 %>% dplyr::filter(total < 2))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  pnOver = ifelse(gene %in% pnOver8, "pnOver8",
                  ifelse(gene %in% pnOver6, "pnOver6",
                         ifelse(gene %in% pnOver4, "pnOver4",
                                ifelse(gene %in% pnOver2, "pnOver2",
                                       ifelse(gene %in% pnOver0, "pnOver0", NA)))))) %>%
  drop_na(pnOver)
(SKIP) GO for each group
# GOfigDir <- here(figDir, "../GO")
# getGO("pnOver8", GOfigDir, pnOver8)
# getGO("pnOver6", GOfigDir, pnOver6)
# getGO("pnOver4", GOfigDir, pnOver4)
# getGO("pnOver2", GOfigDir, pnOver2)
# getGO("pnOver0", GOfigDir, pnOver0)
# 
# #####################
# GO0.df <- as.data.frame(enrichGO(gene = pnOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO2.df <- as.data.frame(enrichGO(gene = pnOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO4.df <- as.data.frame(enrichGO(gene = pnOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO6.df <- as.data.frame(enrichGO(gene = pnOver6, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO8.df <- as.data.frame(enrichGO(gene = pnOver8, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# 
# 
# subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver0") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver2") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver4") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset6 <- GO6.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver6") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset8 <- GO8.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "pnOver8") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# 
# 
# GOlist <- factor(c("GO:0006397", "GO:0008380", "GO:0022613", "GO:0034470",
#                    "GO:0016055", "GO:0007389", "GO:0048562", "GO:0045165", 
#                    "GO:0072001", "GO:0007517", "GO:0048705"))
# 
# data <- bind_rows(bind_rows(bind_rows(subset0, subset2), subset4), subset8) %>%
#   dplyr::filter(ID %in% GOlist)
# 
# p <- ggplot(data, aes(x = group, y = Description, color = p.adjust, size = gr)) + 
#   geom_point() + theme_bw() +
#   scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
#   scale_size_continuous(range = c(0, 3)) +
#   labs(x = NULL, y = NULL) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- here(figDir, "..", "GO", "GO_groups_pn")
# height = 2
# width = 3.3
# svglite(paste0(fileName, ".svg"), height = height, width = width)
# print(p)
# dev.off()
loop score
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(pnOver ==group1) )$mean_diff_score
#   distance2 <- (data %>% dplyr::filter(pnOver ==group2) )$mean_diff_score
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# pv02 <- round(getPvalWilcox(temp, "pnOver0", "pnOver2"), 5)
# pv24 <- round(getPvalWilcox(temp, "pnOver2", "pnOver4"), 5)
# pv46 <- round(getPvalWilcox(temp, "pnOver4", "pnOver6"), 5)
# pv08 <- round(getPvalWilcox(temp, "pnOver0", "pnOver8"), 5)
# pv28 <- round(getPvalWilcox(temp, "pnOver2", "pnOver8"), 5)
# pv48 <- round(getPvalWilcox(temp, "pnOver4", "pnOver8"), 5)
# pv68 <- round(getPvalWilcox(temp, "pnOver6", "pnOver8"), 5)


p <- ggplot(temp, aes(x = pnOver, y = mean_diff_score)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0, label = paste0("pv02: ", convPvalue(pv02), "\n",
  #                                               "pv24: ", convPvalue(pv24), "\n",
  #                                               "pv46: ", convPvalue(pv46), "\n",
  #                                               "pv68: ", convPvalue(pv68), "\n",
  #                                               "pv48: ", convPvalue(pv48), "\n",
  #                                               "pv28: ", convPvalue(pv28), "\n",
  #                                               "pv08: ", convPvalue(pv08), "\n"), 
  #          color = "black", hjust = 0, size = 3)

   
fileName <- paste0("diffScore_barplot_pnGroup_A485_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
#
#  getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(pnOver ==group1) )$log2FoldChange
#   distance2 <- (data %>% dplyr::filter(pnOver ==group2) )$log2FoldChange
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
#  
# pv02 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver2"), 5)
# pv04 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver4"), 5)
# pv06 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver6"), 5)
# pv08 <- round(getPvalWilcox(tempDown, "pnOver0", "pnOver8"), 5)
# pv24 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver4"), 5)
# pv26 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver6"), 5)
# pv28 <- round(getPvalWilcox(tempDown, "pnOver2", "pnOver8"), 5)
# pv46 <- round(getPvalWilcox(tempDown, "pnOver4", "pnOver6"), 5)
# pv48 <- round(getPvalWilcox(tempDown, "pnOver4", "pnOver8"), 5)
# pv68 <- round(getPvalWilcox(tempDown, "pnOver6", "pnOver8"), 5)




p <- ggplot(tempDown, aes(x = pnOver, y = log2FoldChange)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = -0.5, label = paste0("pv02: ", convPvalue(pv02), "\n",
  #                                                  "pv04: ", convPvalue(pv04), "\n",
  #                                                  "pv06: ", convPvalue(pv06), "\n",
  #                                                  "pv08: ", convPvalue(pv08), "\n",
  #                                                  "pv24: ", convPvalue(pv24), "\n",
  #                                                  "pv26: ", convPvalue(pv26), "\n",
  #                                                  "pv28: ", convPvalue(pv28), "\n",
  #                                                  "pv46: ", convPvalue(pv46), "\n",
  #                                                  "pv48: ", convPvalue(pv48), "\n",
  #                                                  "pv68: ", convPvalue(pv68), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(-1, 0))

  
fileName <- paste0("log2FC_barplot_pnGroup_A485_vs_DMSO_down")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
#  
# pv02 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver2"), 5)
# pv04 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver4"), 5)
# pv06 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver6"), 5)
# pv08 <- round(getPvalWilcox(tempUp, "pnOver0", "pnOver8"), 5)
# pv24 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver4"), 5)
# pv26 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver6"), 5)
# pv28 <- round(getPvalWilcox(tempUp, "pnOver2", "pnOver8"), 5)
# pv46 <- round(getPvalWilcox(tempUp, "pnOver4", "pnOver6"), 5)
# pv48 <- round(getPvalWilcox(tempUp, "pnOver4", "pnOver8"), 5)
# pv68 <- round(getPvalWilcox(tempUp, "pnOver6", "pnOver8"), 5)
# 



p <- ggplot(tempUp, aes(x = pnOver, y = log2FoldChange)) + geom_violin(aes(fill = pnOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = pnOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0.5, label = paste0("pv02: ", convPvalue(pv02), "\n",
  #                                                  "pv04: ", convPvalue(pv04), "\n",
  #                                                  "pv06: ", convPvalue(pv06), "\n",
  #                                                  "pv08: ", convPvalue(pv08), "\n",
  #                                                  "pv24: ", convPvalue(pv24), "\n",
  #                                                  "pv26: ", convPvalue(pv26), "\n",
  #                                                  "pv28: ", convPvalue(pv28), "\n",
  #                                                  "pv46: ", convPvalue(pv46), "\n",
  #                                                  "pv48: ", convPvalue(pv48), "\n",
  #                                                  "pv68: ", convPvalue(pv68), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_pnGroup_A485_vs_DMSO_up")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-S number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene




## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


temp <- temp %>% dplyr::mutate(
  psOver = ifelse(gene %in% psOver4, "psOver4",
                  ifelse(gene %in% psOver3, "psOver3",
                         ifelse(gene %in% psOver2, "psOver2",
                                ifelse(gene %in% psOver1, "psOver1",
                                       ifelse(gene %in% psOver0, "psOver0", NA)))))) %>%
  drop_na(psOver)
(SKIP) GO for each group
# GOfigDir <- here(figDir, "../GO")
# getGO("psOver4", GOfigDir, psOver4)
# getGO("psOver3", GOfigDir, psOver3)
# getGO("psOver2", GOfigDir, psOver2)
# getGO("psOver1", GOfigDir, psOver1)
# getGO("psOver0", GOfigDir, psOver0)
# 
# #####################
# GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# 
# 
# subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver0") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver1") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver2") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver3") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver4") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# 
# 
# GOlist <- factor(c("GO:0006397", "GO:0008380", "GO:0022613", "GO:0034470",
#                    "GO:0016055", "GO:0007389", "GO:0048562", "GO:0045165", 
#                    "GO:0072001", "GO:0007517", "GO:0048705", "GO:0003002"))
# 
# data <- bind_rows(bind_rows(bind_rows(bind_rows(subset0, subset1), subset2), subset3), subset4) %>%
#   dplyr::filter(ID %in% GOlist)
# 
# p <- ggplot(data, aes(x = group, y = Description, color = p.adjust, size = gr)) + 
#   geom_point() + theme_bw() +
#   scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
#   scale_size_continuous(range = c(0, 3)) +
#   labs(x = NULL, y = NULL) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- here(figDir, "..", "GO", "GO_groups_ps")
# height = 2
# width = 3.4
# svglite(paste0(fileName, ".svg"), height = height, width = width)
# print(p)
# dev.off()
loop score
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)
# 

p <- ggplot(temp, aes(x = psOver, y = mean_diff_score)) + geom_violin(aes(fill = psOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = psOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n", 
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3)

  
fileName <- paste0("diffScore_barplot_psGroup_A485_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
#
#  getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
#  
# ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)
# 
# ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)


p <- ggplot(tempDown, aes(x = psOver, y = log2FoldChange)) + geom_violin(aes(fill = psOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = psOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(-1, 0))

  
fileName <- paste0("log2FC_barplot_psGroup_A485_vs_DMSO_down")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
#  
# ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)
# 



p <- ggplot(tempUp, aes(x = psOver, y = log2FoldChange)) + geom_violin(aes(fill = psOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = psOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_psGroup_A485_vs_DMSO_up")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-E number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers

peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


temp <- temp %>% dplyr::mutate(
  peOver = ifelse(gene %in% peOver4, "peOver4",
                  ifelse(gene %in% peOver3, "peOver3",
                         ifelse(gene %in% peOver2, "peOver2",
                                ifelse(gene %in% peOver1, "peOver1",
                                       ifelse(gene %in% peOver0, "peOver0", NA)))))) %>%
  drop_na(peOver)
(SKIP) GO for each group
# GOfigDir <- here(figDir, "../GO")
# getGO("peOver4", GOfigDir, psOver4)
# getGO("peOver3", GOfigDir, psOver3)
# getGO("peOver2", GOfigDir, psOver2)
# getGO("peOver1", GOfigDir, psOver1)
# getGO("peOver0", GOfigDir, psOver0)
# 
# #####################
# GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# 
# 
# subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver0") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver1") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver2") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver3") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver4") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# 
# 
# GOlist <- factor(c("GO:0006397", "GO:0008380", "GO:0022613", "GO:0034470",
#                    "GO:0016055", "GO:0007389", "GO:0048562", "GO:0045165", 
#                    "GO:0072001", "GO:0007517", "GO:0048705", 
#                    "GO:0040029", "GO:0010165"))
# 
# data <- bind_rows(bind_rows(bind_rows(subset0, subset1), subset2), subset4) %>%
#   dplyr::filter(ID %in% GOlist)
# 
# p <- ggplot(data, aes(x = group, y = Description, color = p.adjust, size = gr)) + 
#   geom_point() + theme_bw() +
#   scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
#   scale_size_continuous(range = c(0, 3)) +
#   labs(x = NULL, y = NULL) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- here(figDir, "..", "GO", "GO_groups_pe")
# height = 2
# width = 3.4
# svglite(paste0(fileName, ".svg"), height = height, width = width)
# print(p)
# dev.off()
loop score
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)


p <- ggplot(temp, aes(x = peOver, y = mean_diff_score)) + geom_violin(aes(fill = peOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = peOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ",convPvalue( ps14), "\n",
  #                                               "ps04: ",convPvalue( ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3)

  
fileName <- paste0("diffScore_barplot_peGroup_A485_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
#
#  getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
#  
# ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)


p <- ggplot(tempDown, aes(x = peOver, y = log2FoldChange)) + geom_violin(aes(fill = peOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = peOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(-1, 0))

  
fileName <- paste0("log2FC_barplot_peGroup_A485_vs_DMSO_down")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
 
# ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)
# 




p <- ggplot(tempUp, aes(x = peOver, y = log2FoldChange)) + geom_violin(aes(fill = peOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = peOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_peGroup_A485_vs_DMSO_up")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

Grouping with P-P number

Grouping
# temp2 contains genes from group 1, 2, 5, 8 and loop counts
#calculating diff score and log2fc distribution based on p-n numbers
ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene



## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_A485_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_A485_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  drop_na(shrinked_log2FC)


temp <- temp %>% dplyr::mutate(
  ppOver = ifelse(gene %in% ppOver4, "ppOver4",
                  ifelse(gene %in% ppOver3, "ppOver3",
                         ifelse(gene %in% ppOver2, "ppOver2",
                                ifelse(gene %in% ppOver1, "ppOver1",
                                       ifelse(gene %in% ppOver0, "ppOver0", NA)))))) %>%
  drop_na(ppOver)
(SKIP) GO for each group
# GOfigDir <- here(figDir, "../GO")
# getGO("ppOver4", GOfigDir, psOver4)
# getGO("ppOver3", GOfigDir, psOver3)
# getGO("ppOver2", GOfigDir, psOver2)
# getGO("ppOver1", GOfigDir, psOver1)
# getGO("ppOver0", GOfigDir, psOver0)
# 
# #####################
# GO0.df <- as.data.frame(enrichGO(gene = psOver0, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO1.df <- as.data.frame(enrichGO(gene = psOver1, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO2.df <- as.data.frame(enrichGO(gene = psOver2, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO3.df <- as.data.frame(enrichGO(gene = psOver3, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# GO4.df <- as.data.frame(enrichGO(gene = psOver4, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP"))
# 
# 
# subset0 <- GO0.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver0") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset1 <- GO1.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver1") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset2 <- GO2.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver2") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset3 <- GO3.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver3") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# subset4 <- GO4.df %>% dplyr::select(ID, Description, GeneRatio, p.adjust) %>% dplyr::mutate(group = "psOver4") %>%
#   dplyr::mutate(
#     gr = sapply(GeneRatio, function(x) {
#       # Split the string by "/"
#       parts <- unlist(strsplit(x, "/"))
#       # Convert to numeric and perform the division
#       as.numeric(parts[1]) / as.numeric(parts[2])
#     })
#   ) %>% dplyr::arrange(desc(gr))
# 
# 
# GOlist <- factor(c("GO:0006397", "GO:0008380", "GO:0022613", "GO:0034470",
#                    "GO:0016055", "GO:0007389", "GO:0048562", "GO:0045165", 
#                    "GO:0072001", "GO:0007517", "GO:0048705", "GO:0003002", "GO:0009411"))
# 
# data <- bind_rows(bind_rows(subset0, subset1), subset3) %>%
#   dplyr::filter(ID %in% GOlist)
# 
# p <- ggplot(data, aes(x = group, y = Description, color = p.adjust, size = gr)) + 
#   geom_point() + theme_bw() +
#   scale_color_gradient(low = "red", high = "blue", limits = c(0, 0.05)) +
#   scale_size_continuous(range = c(0, 3)) +
#   labs(x = NULL, y = NULL) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- here(figDir, "..", "GO", "GO_groups_pp")
# height = 2
# width = 3.4
# svglite(paste0(fileName, ".svg"), height = height, width = width)
# print(p)
# dev.off()
loop score
# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$mean_diff_score
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$mean_diff_score
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# 
# ps01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(temp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(temp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)


p <- ggplot(temp, aes(x = ppOver, y = mean_diff_score)) + geom_violin(aes(fill = ppOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = ppOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3)

  
fileName <- paste0("diffScore_barplot_ppGroup_A485_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
#
#  getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(psOver ==group1) )$log2FoldChange
#   distance2 <- (data %>% dplyr::filter(psOver ==group2) )$log2FoldChange
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }

tempDown <- temp %>% dplyr::filter(log2FoldChange < 0)
#  
# ps01 <- round(getPvalWilcox(tempDown, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempDown, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempDown, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempDown, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempDown, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempDown, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(tempDown, "psOver0", "psOver4"), 5)



p <- ggplot(tempDown, aes(x = ppOver, y = log2FoldChange)) + geom_violin(aes(fill = ppOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = ppOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = -0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(-1, 0))

  
fileName <- paste0("log2FC_barplot_ppGroup_A485_vs_DMSO_down")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



tempUp <- temp %>% dplyr::filter(log2FoldChange > 0)
#  
# ps01 <- round(getPvalWilcox(tempUp, "psOver0", "psOver1"), 5)
# ps12 <- round(getPvalWilcox(tempUp, "psOver1", "psOver2"), 5)
# ps23 <- round(getPvalWilcox(tempUp, "psOver2", "psOver3"), 5)
# ps34 <- round(getPvalWilcox(tempUp, "psOver3", "psOver4"), 5)
# ps24 <- round(getPvalWilcox(tempUp, "psOver2", "psOver4"), 5)
# ps14 <- round(getPvalWilcox(tempUp, "psOver1", "psOver4"), 5)
# ps04 <- round(getPvalWilcox(tempUp, "psOver0", "psOver4"), 5)
# 
# 



p <- ggplot(tempUp, aes(x = ppOver, y = log2FoldChange)) + geom_violin(aes(fill = ppOver), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + theme_classic() + 
  stat_summary(aes(group = ppOver), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  geom_hline(yintercept = 0)
  # annotate("text", x = 1, y = 0.5, label = paste0("ps01: ", convPvalue(ps01), "\n",
  #                                               "ps12: ", convPvalue(ps12), "\n",
  #                                               "ps23: ", convPvalue(ps23), "\n",
  #                                               "ps34: ", convPvalue(ps34), "\n",
  #                                               "ps24: ", convPvalue(ps24), "\n",
  #                                               "ps14: ", convPvalue(ps14), "\n",
  #                                               "ps04: ", convPvalue(ps04), "\n"), 
  #          color = "black", hjust = 0, size = 3) + coord_cartesian(ylim = c(0, 1))

  
fileName <- paste0("log2FC_barplot_ppGroup_A485_vs_DMSO_up")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[2.13] How to define multiconnected hub using regulatory loops?

# IMPORTING GENE ANNO DATA FOR P-N LOOPS
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                 diffCutoff = 0.2,
                                 annoList = c("P-P", "P-E", "P-S", "P-X")) %>% dplyr::select(c(1, 2, 3, 4, 5, 6, 11, 12, 13, 22, 23, 24, 25, 27, 28))

data <- fread(here(consensusDir, paste0(name, ".tsv"))) %>% dplyr::select(c(1, 2, 3, 4, 5, 6, 11, 12, 13, 22, 23, 24, 25, 27)) %>%
  dplyr::mutate(binSize = end1 - start1,
                adj_start1 = ifelse(binSize == 5000, start1,
                                    ifelse(binSize == 10000, start1,
                                           start1 + 10000)),
                adj_end1 = adj_start1 + 5000,
                adj_start2 = ifelse(binSize == 5000, start2,
                                    ifelse(binSize == 10000, start2,
                                           start2 + 10000)),
                adj_end2 = adj_start2 + 5000,
                anchor1 = paste(chrom1, adj_start1, adj_end1, sep = "_"),
                anchor2 = paste(chrom2, adj_start2, adj_end2, sep = "_"))

# data <- fread(here(consensusDir, paste0(name, ".tsv"))) %>% dplyr::select(c(1, 2, 3, 4, 5, 6, 11, 12, 13, 22, 23, 24, 25, 27)) %>% 
#   dplyr::mutate(binSize = end1 - start1,
#                 adj_start1 = ifelse(binSize == 5000, start1,
#                                     ifelse(binSize == 10000, start1+5000,
#                                            start1 + 10000)),
#                 adj_end1 = adj_start1 + 5000,
#                 adj_start2 = ifelse(binSize == 5000, start2,
#                                     ifelse(binSize == 10000, start2 + 5000,
#                                            start2 + 10000)),
#                 adj_end2 = adj_start2 + 5000,
#                 anchor1 = paste(chrom1, adj_start1, adj_end1, sep = "_"),
#                 anchor2 = paste(chrom2, adj_start2, adj_end2, sep = "_"))

data.reg <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "P-S", "P-X", "E-E", "E-S", "E-X"))

## Graph
#install.packages("igraph")
library(igraph)

# To be able to construct a graph, each anchor need to have same resolution.
# Shink the size to 10 kb
# If the anchor is 25kb, choose the middle 5kb bin
# If the anchor is 10kb, choose the left 5kb bin

graph <- graph_from_data_frame(data.reg %>% dplyr::select(anchor1, anchor2))
components <- components(graph)
data.reg$hub <- components$membership[data.reg$anchor1]

temp.bedpe <- data.reg %>% dplyr::select(chrom1, adj_start1, adj_end1, chrom2, adj_start2, adj_end2)
fwrite(temp.bedpe, here(consensusDir, paste0(name, "_regulatory_5kbAdj.bedpe")), 
       col.names = FALSE,row.names = FALSE, sep = "\t")  

hubNum <- data.reg %>% group_by(hub) %>% summarise(count = n())

# Hub size distribution
p <- ggplot(hubNum, aes(x = count)) + geom_histogram(binwidth  = 1) + theme_classic() + 
  scale_y_log10()

svglite(here(figDir, "hub_size_distribution.svg"), height = 2, width = 2)
print(p)
dev.off()

data.reg <- data.reg %>% dplyr::left_join(hubNum, by = "hub") 
data.reg <- data.reg %>% dplyr::mutate(peakID = paste(chrom1, start1, start2, sep = "_"))

# Exporting regulatory loops with specific hub size
temp.bedpe <- data.reg %>% dplyr::filter(count >= 3) %>% dplyr::select(chrom1, adj_start1, adj_end1, chrom2, adj_start2, adj_end2)
fwrite(temp.bedpe, here(consensusDir, paste0(name, "_regulatory_5kbAdj_hub3.bedpe")), 
       col.names = FALSE,row.names = FALSE, sep = "\t")  

temp.bedpe <- data.reg %>% dplyr::filter(count >= 5) %>% dplyr::select(chrom1, adj_start1, adj_end1, chrom2, adj_start2, adj_end2)
fwrite(temp.bedpe, here(consensusDir, paste0(name, "_regulatory_5kbAdj_hub5.bedpe")), 
       col.names = FALSE,row.names = FALSE, sep = "\t")

temp.bedpe <- data.reg %>% dplyr::filter(count >= 10) %>% dplyr::select(chrom1, adj_start1, adj_end1, chrom2, adj_start2, adj_end2)
fwrite(temp.bedpe, here(consensusDir, paste0(name, "_regulatory_5kbAdj_hub10.bedpe")), 
       col.names = FALSE,row.names = FALSE, sep = "\t")


# Adding gene annotation to hubs
genePeakPair <- geneAnnoData %>% dplyr::mutate(peakID = paste(chrom1, start1, start2, sep = "_")) %>% dplyr::select(peakID, gene)
data.reg <- data.reg %>% dplyr::left_join(genePeakPair, by = "peakID")

# During unnesting, E-N loops without gene annotated are removed
data.reg <- data.reg %>% unnest(gene) %>% dplyr::mutate(
  group = ifelse(gene %in% gene.group1, "group1",
                 ifelse(gene %in% gene.group2, "group2",
                        ifelse(gene %in% gene.group3, "group3",
                               ifelse(gene %in% gene.group4, "group4",
                                      ifelse(gene %in% gene.group5, "group5",
                                             ifelse(gene %in% gene.group6, "group6",
                                                    ifelse(gene %in% gene.group7, "group7",
                                                           ifelse(gene %in% gene.group8, "group8",
                                                                  ifelse(gene %in% gene.group9, "group9", NA)))))))))
)


temp <- data.reg %>% dplyr::select(gene, hub, count, group) %>%
  group_by(gene) %>% slice_max(count, with_ties = FALSE) %>%
  dplyr::filter(group %in% c("group1", "group2", "group5", "group8"))


# TEMP START
# TEMP START
geneList.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))
geneList.group1.temp <- geneList.group1 %>% dplyr::left_join(temp, by = c("gene"))
# TEMP END

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$count
  distance2 <- (data %>% dplyr::filter(group ==group2) )$count
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


pv12 <- round(getPvalWilcox(tempSum,"group1", "group2"), 5)
pv15 <- round(getPvalWilcox(tempSum,"group1", "group5"), 5)
pv18 <- round(getPvalWilcox(tempSum,"group1", "group8"), 5)
pv25 <- round(getPvalWilcox(tempSum,"group2", "group5"), 5)
pv28 <- round(getPvalWilcox(tempSum,"group2", "group8"), 5)
pv58 <- round(getPvalWilcox(tempSum,"group5", "group8"), 5)


p <- ggplot(temp, aes(x = group, y = count, fill = group)) + 
  geom_boxplot(width = 0.5, outlier.shape = NA) + theme_classic() + 
    scale_y_continuous(breaks = seq(0, 30, by = 5), limits = c(0, 30)) + 

  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")  +
  annotate("text", x = 1, y = 3, label = paste0("pv12: ", pv12, "\n",
                                                "pv15: ", pv15, "\n",
                                                "pv18: ", pv18, "\n",
                                                "pv25: ", pv25, "\n",
                                                "pv28: ", pv28, "\n",
                                                "pv58: ", pv58, "\n"), 
           color = "black", hjust = 0, size = 1) +  theme(legend.position = "none")


fileName <- paste0("countHub_barplot_diffGroup_dTAG_vs_DMSO")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[2.14] Looking deeper into TAD and insulation

Insulation score of TSS?

Importing insulation score

# Import insulation score calculated with python
resultDir <- here("../../result")
insScore.DMSO <- fread(here(resultDir, "TAD", "insulationScore_25kb_G1DMSO.tsv")) %>% 
  dplyr::select(c("chrom", "start", "end", "log2_insulation_score_125000")) %>%
  dplyr::mutate(binID = paste(chrom, start, end, sep = "_"))
colnames(insScore.DMSO) <- c("chrom", "start", "end", "insulationScore", "binID")
insScore.dTAG <- fread(here(resultDir, "TAD", "insulationScore_25kb_G1dTAG.tsv")) %>% 
  dplyr::select(c("chrom", "start", "end", "log2_insulation_score_125000")) %>%
  dplyr::mutate(binID = paste(chrom, start, end, sep = "_"))
colnames(insScore.dTAG) <- c("chrom", "start", "end", "insulationScore", "binID")

#insScore <- full_join(insScore.DMSO, insScore.dTAG, by = c("binID")) %>%
#  dplyr::select(binID, chrom.x, start.x, end.x, insulationScore.x, insulationScore.y) 

#colnames(insScore) <- c("binID", "chr", "start", "end", "insulation_score_DMSO", "insulation_scoare_dTAG")

#View(insScore)

Linking to gene

gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, V5, V1, TSS)
colnames(gene.TSS.tb) <- c("ensembl", "gene", "chr", "TSS")

getInsulationScore <- function(chr, TSS, insScore.tb){
  temp.tb <- insScore.tb %>% dplyr::filter(chrom == chr, start < TSS, end > TSS)
  out <- temp.tb$insulationScore
  if(length(out) < 1){
    return(NA)
  }else{
    return(temp.tb$insulationScore)
  }
}

gene.insScore.all <- gene.TSS.tb %>% rowwise() %>% dplyr::mutate(
  log2_insScore_DMSO = getInsulationScore(chr, TSS, insScore.DMSO),
  insScore_DMSO = 2^log2_insScore_DMSO,
  log2_insScore_dTAG = getInsulationScore(chr, TSS, insScore.dTAG),
  insScore_dTAG = 2^log2_insScore_dTAG,
  diff_insScore = insScore_dTAG - insScore_DMSO)

Checking insulation score of the nearest TAD

# Importing TAD boundaries
tad_boundary <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_boundaries_G1DMSO.bed"))
colnames(tad_boundary) <- c("chr", "start", "end")
tad_boundary <- tad_boundary %>% dplyr::mutate(tad_id = paste(chr, start, end, sep = "_"),
                                               center = (start + end)/2)

findClosestTADBoundary <- function(chrom, TSS, tad_boundary){
  temp <- tad_boundary %>% dplyr::filter(chr == chrom) %>%
    dplyr::mutate(distance = abs(center - TSS)) %>%
    slice_min(distance)
  if(nrow(temp) == 1){
      return(temp$center)
  }else{
    return(NA)
  }
}


gene.insScore.all <- gene.insScore.all %>% rowwise() %>%
  dplyr::mutate(closestBoundary = findClosestTADBoundary(chr, TSS, tad_boundary),
                log2_boundaryInsScore_DMSO = getInsulationScore(chr, closestBoundary, insScore.DMSO),
                boundaryInsScore_DMSO = 2^log2_boundaryInsScore_DMSO,
                log2_boundaryInsScore_dTAG = getInsulationScore(chr, closestBoundary, insScore.dTAG),
                boundaryInsScore_dTAG = 2^log2_boundaryInsScore_dTAG,
                diff_boundaryInsScore = boundaryInsScore_dTAG - boundaryInsScore_DMSO)

saveRDS(gene.insScore.all, here(resultDir, "gene.insScore.all.rds"))
gene.insScore.all <- readRDS(here(resultDir, "gene.insScore.all.rds"))
Plotting for binary groups
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2", NA))) %>% 
  dplyr::filter(!is.na(group))


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_insScore <- function(temp.tb, note, ymin = -1.5, ymax = 0){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  
  p <- ggplot(temp.tb, aes(x = ".", fill = group, y = -score)) + 
    labs(x = NULL, y = "- Insulation score") +  # Remove x-axis title
    scale_fill_manual(values = rev((c("#777777", "#F28E2C")))) +

    introdataviz::geom_split_violin(linewidth = lineMedium * mmToLineUnit, lineend = "square",
                                    alpha = .4) +
    geom_boxplot(width = 0.3, color = "black",
                 linewidth = lineMedium * mmToLineUnit, lineend = "square",
                 outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + theme_classic() +
    stat_summary(
      aes(group = group), fun = mean,
      geom = "point", shape = 21, size = 0.5,
      fill = "black", color = "black", position = position_dodge(.3)
    ) +
    
    # 
    # geom_violin(aes(fill = group), color = "black", linewidth = lineThick*mmToLineUnit, lineend = "square", show.legend = FALSE) + 
    # geom_boxplot(width = 0.1,  color = "black", linewidth = lineThick*mmToLineUnit, lineend = "square",
    #              outlier.size = 1, outlier.stroke = NA) +
    # stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 1, fill = "red", color = "black") + 
    geom_hline(yintercept = 0, linewidth = lineThick*mmToLineUnit) +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p12: ", convPvalue(p12)),
             color = "black", hjust = 0, size = 3) +
    theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )+   guides(
      fill = guide_legend(
        keywidth = 0.2,  # Adjust the width of the legend keys
        keyheight = 0.2  # Adjust the height of the legend keys
      ))
      
      
  fileName <- paste0("insulation_score_binaryGroup_", note)
  width <- panelSize(1.55)*mmToInch
height <- panelSize(1.2)*mmToInch
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO_binaryGroup", ymin = -1.1, ymax = -0.5)

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG_binaryGroup", ymin =  -1.1, ymax = -0.5)

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff_binaryGroup", ymin = -0.3, ymax = 0.1)
Plotting for groups
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2",
                        ifelse(ensembl %in% group5, "group5",
                               ifelse(ensembl %in% group8, "group8", NA))))) %>% 
  dplyr::filter(!is.na(group))


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO")

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG")

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff", ymin = -0.5, ymax = 1)
Plotting for P-N
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

pnOver8 <- (temp2 %>% dplyr::filter(total >= 8))$gene
pnOver6 <- (temp2 %>% dplyr::filter(total >= 6, total < 8))$gene
pnOver4 <- (temp2 %>% dplyr::filter(total >= 4, total < 6))$gene
pnOver2 <- (temp2 %>% dplyr::filter(total >= 2, total < 4))$gene
pnOver0 <- (temp2 %>% dplyr::filter(total < 2))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% pnOver8, "p8",
                 ifelse(ensembl %in% pnOver6, "p6",
                        ifelse(ensembl %in% pnOver4, "p4",
                               ifelse(ensembl %in% pnOver2, "p2", 
                                      ifelse(ensembl %in% pnOver0, "p0", NA))))))  %>% 
  dplyr::filter(!is.na(group))

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p02 <- round(getPvalWilcox(temp.tb, "p0", "p2"), 5)
  p24 <- round(getPvalWilcox(temp.tb, "p2", "p4"), 5)
  p46 <- round(getPvalWilcox(temp.tb, "p4", "p6"), 5)
  p68 <- round(getPvalWilcox(temp.tb, "p6", "p8"), 5)
  p48 <- round(getPvalWilcox(temp.tb, "p4", "p8"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "p2", "p8"), 5)
  p08 <- round(getPvalWilcox(temp.tb, "p0", "p8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p02: ", convPvalue(p02), "\n",
                                                         "p24: ", convPvalue(p24), "\n",
                                                         "p46: ", convPvalue(p46), "\n",
                                                         "p68: ", convPvalue(p68), "\n",
                                                         "p48: ", convPvalue(p48), "\n",
                                                         "p28: ",convPvalue( p28), "\n",
                                                         "p08: ",convPvalue( p08), "\n"),
             color = "black", hjust = 0, size = 3)  +
    scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO_P-N")

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG_P-N")

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff_P-N", ymin = -0.5, ymax = 1)
Plotting for P-S
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% psOver4, "p4",
                 ifelse(ensembl %in% psOver3, "p3",
                        ifelse(ensembl %in% psOver2, "p2",
                               ifelse(ensembl %in% psOver1, "p1", 
                                      ifelse(ensembl %in% psOver0, "p0", NA))))))  %>% 
  dplyr::filter(!is.na(group))

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p01 <- round(getPvalWilcox(temp.tb, "p0", "p1"), 5)
  p12 <- round(getPvalWilcox(temp.tb, "p1", "p2"), 5)
  p23 <- round(getPvalWilcox(temp.tb, "p2", "p3"), 5)
  p34 <- round(getPvalWilcox(temp.tb, "p3", "p4"), 5)
  p24 <- round(getPvalWilcox(temp.tb, "p2", "p4"), 5)
  p14 <- round(getPvalWilcox(temp.tb, "p1", "p4"), 5)
  p04 <- round(getPvalWilcox(temp.tb, "p0", "p4"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p01: ", convPvalue(p01), "\n",
                                                         "p12: ", convPvalue(p12), "\n",
                                                         "p23: ", convPvalue(p23), "\n",
                                                         "p34: ", convPvalue(p34), "\n",
                                                         "p24: ", convPvalue(p24), "\n",
                                                         "p14: ",convPvalue( p14), "\n",
                                                         "p04: ",convPvalue( p04), "\n"), 
             color = "black", hjust = 0, size = 3) +
    scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO_P-S")

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG_P-S")

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff_P-S", ymin = -0.5, ymax = 1)
Plotting for P-E
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% peOver4, "p4",
                 ifelse(ensembl %in% peOver3, "p3",
                        ifelse(ensembl %in% peOver2, "p2",
                               ifelse(ensembl %in% peOver1, "p1", 
                                      ifelse(ensembl %in% peOver0, "p0", NA))))))  %>% 
  dplyr::filter(!is.na(group))

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p01 <- round(getPvalWilcox(temp.tb, "p0", "p1"), 5)
  p12 <- round(getPvalWilcox(temp.tb, "p1", "p2"), 5)
  p23 <- round(getPvalWilcox(temp.tb, "p2", "p3"), 5)
  p34 <- round(getPvalWilcox(temp.tb, "p3", "p4"), 5)
  p24 <- round(getPvalWilcox(temp.tb, "p2", "p4"), 5)
  p14 <- round(getPvalWilcox(temp.tb, "p1", "p4"), 5)
  p04 <- round(getPvalWilcox(temp.tb, "p0", "p4"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p01: ", convPvalue(p01), "\n",
                                                         "p12: ", convPvalue(p12), "\n",
                                                         "p23: ", convPvalue(p23), "\n",
                                                         "p34: ", convPvalue(p34), "\n",
                                                         "p24: ", convPvalue(p24), "\n",
                                                         "p14: ",convPvalue( p14), "\n",
                                                         "p04: ",convPvalue( p04), "\n"), 
             color = "black", hjust = 0, size = 3) +
    scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO_P-E")

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG_P-E")

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff_P-E", ymin = -0.5, ymax = 1)
Plotting for P-P
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene


gene.insScore <- gene.insScore.all %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% ppOver4, "p4",
                 ifelse(ensembl %in% ppOver3, "p3",
                        ifelse(ensembl %in% ppOver2, "p2",
                               ifelse(ensembl %in% ppOver1, "p1", 
                                      ifelse(ensembl %in% ppOver0, "p0", NA))))))  %>% 
  dplyr::filter(!is.na(group))

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$score
  distance2 <- (data %>% dplyr::filter(group ==group2) )$score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

plot_insScore <- function(temp.tb, note, ymin = 0, ymax = 1.5){
  p01 <- round(getPvalWilcox(temp.tb, "p0", "p1"), 5)
  p12 <- round(getPvalWilcox(temp.tb, "p1", "p2"), 5)
  p23 <- round(getPvalWilcox(temp.tb, "p2", "p3"), 5)
  p34 <- round(getPvalWilcox(temp.tb, "p3", "p4"), 5)
  p24 <- round(getPvalWilcox(temp.tb, "p2", "p4"), 5)
  p14 <- round(getPvalWilcox(temp.tb, "p1", "p4"), 5)
  p04 <- round(getPvalWilcox(temp.tb, "p0", "p4"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p01: ", convPvalue(p01), "\n",
                                                         "p12: ", convPvalue(p12), "\n",
                                                         "p23: ", convPvalue(p23), "\n",
                                                         "p34: ", convPvalue(p34), "\n",
                                                         "p24: ", convPvalue(p24), "\n",
                                                         "p14: ",convPvalue( p14), "\n",
                                                         "p04: ",convPvalue( p04), "\n"), 
             color = "black", hjust = 0, size = 3) +
    scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# DMSO
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_DMSO)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_DMSO_P-P")

# dTAG
temp.tb <- gene.insScore %>% dplyr::select(group, boundaryInsScore_dTAG)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_dTAG_P-P")

# diff
temp.tb <- gene.insScore %>% dplyr::select(group, diff_boundaryInsScore)
colnames(temp.tb) <- c("group", "score")
plot_insScore(temp.tb, "nearestBoundary_diff_P-P", ymin = -0.5, ymax = 1)

[2.15] TAD distance/size

[2.16] Checking the intensity of RAD21 at TAD boundary

Calculating RAD21 intensity of the nearest TAD boundary

refDir <- here("../..", "reference")

# Importing TAD boundary
tad_boundary <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_boundaries_G1DMSO.bed"))
colnames(tad_boundary) <- c("chr", "start", "end")
tad_boundary <- tad_boundary %>% dplyr::mutate(tad_id = paste(chr, start, end, sep = "_"),
                                               start = start -175000/2,
                                               end = end + 175000/2,
                                               center = (start + end)/2)

# Importing RAD21 bigwig track
bw.RAD21 <- import(here(refDir, "33250_RAD21_ab992_Bruce-4_trim_q20_dedup_black_depthNorm_bin50bp.bw"))

# Create GRanges object for TAD boundaries
tad_ranges <- makeGRangesFromDataFrame(tad_boundary, keep.extra.columns = TRUE)

# Find overlaps between all TAD boundaries and RAD21 bigwig data
overlaps <- findOverlaps(tad_ranges, bw.RAD21)

# Extract overlapping regions and scores from the BigWig
overlapping_bw <- bw.RAD21[subjectHits(overlaps)]
overlapping_tads <- tad_ranges[queryHits(overlaps)]

# Aggregate scores by TAD boundary regions


scores <- as_tibble(overlapping_bw) %>%
  dplyr::mutate(tad_id = tad_ranges[queryHits(overlaps)]$tad_id) %>%
  group_by(tad_id) %>%
  summarise(rad21Score = sum(score))

tad_boundary <- tad_boundary %>%
  left_join(scores, by = "tad_id")





# Importing gene
gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, V5, V1, TSS)
colnames(gene.TSS.tb) <- c("ensembl", "gene", "chr", "TSS")


# Find nearest TAD boundary
findClosestTADBoundaryID <- function(chrom, TSS, tad_boundary){
  temp <- tad_boundary %>% dplyr::filter(chr == chrom) %>%
    dplyr::mutate(distance = abs(center - TSS)) %>%
    slice_min(distance)
  if(nrow(temp) == 1){
      return(temp$tad_id)
  }else{
    return(NA)
  }
}
gene.TSS.tb <- gene.TSS.tb %>% rowwise() %>%
  dplyr::mutate(closestBoundary = findClosestTADBoundaryID(chr, TSS, tad_boundary))

temp <- tad_boundary %>% dplyr::select(tad_id, rad21Score)

gene.TSS.tb <- gene.TSS.tb %>% left_join(temp, by = c("closestBoundary" = "tad_id") )
Plotting for groups
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene


gene.TSS.tb.plot <- gene.TSS.tb %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2",
                        ifelse(ensembl %in% group5, "group5",
                               ifelse(ensembl %in% group8, "group8", NA))))) %>% 
  dplyr::filter(!is.na(group))


## Plot distance
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$rad21Score
  distance2 <- (data %>% dplyr::filter(group == group2) )$rad21Score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_rad21ScoreAtBoundary <- function(temp.tb, note){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = rad21Score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + 
    annotate("text", x = 1, y = 20 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("rad21Score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

plot_rad21ScoreAtBoundary(gene.TSS.tb.plot, "group")

[2.17] Checking the density of gene / enhancer within designated TAD

Making TAD gene count

### IMPORTING REQUIRED DATA
# Importing TAD
tad <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_G1DMSO.bedpe"))
colnames(tad) <- c("chr1", "start1", "end1", "chr2", "start2", "end2")
tad <- tad %>% dplyr::mutate(tadID = paste(chr1, start1, end1, sep = "_"))


# Importing gene
gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, V5, V1, TSS)
colnames(gene.TSS.tb) <- c("ensembl", "gene", "chr", "TSS")

# Importing enhancer
peak.H3K27ac <- as_tibble(importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))) %>%
  dplyr::mutate(center = (start + end)/2)


### FUNCTION FOR COUNTING
findItsTAD <- function(chrom, coordinate, tad){
  temp <- tad %>% dplyr::filter(chr1 == chrom,
                                         start1 < coordinate,
                                         end1 > coordinate)
  if(nrow(temp) == 1){
    return(temp$tadID)
  }else{
    return(NA)
  }
}

### Counting each features for TAD
### Counting gene
geneCountPerTAD <- gene.TSS.tb %>% rowwise() %>%
  dplyr::mutate(TAD = findItsTAD(chr, TSS, tad)) %>%
  drop_na() %>%
  group_by(TAD) %>%
  summarize(count = n())

### Counting enhancer

enhCountPerTAD <- peak.H3K27ac %>% rowwise() %>%
  dplyr::mutate(TAD = findItsTAD(seqnames, center, tad)) %>%
  drop_na() %>%
  group_by(TAD) %>%
  summarize(count = n())

### Get TAD sizez
tad.db <- tad %>% left_join(geneCountPerTAD, by = c("tadID" = "TAD"), ) %>%
  left_join(enhCountPerTAD, by = c("tadID" = "TAD")) %>%
  dplyr::select(c(1, 2, 3, 7, 8, 9)) %>%
  mutate_all(~replace(., is.na(.), 0))

colnames(tad.db) <- c("chr", "start", "end", "tadID", "geneCount", "enhCount")

tad.db <- tad.db %>% dplyr::mutate(
  tadSize = end - start,
  geneDensity = geneCount/tadSize * 100e3,
  enhDensity = enhCount/tadSize* 100e3,
  regDensity = (geneCount + enhCount)/tadSize* 100e3
)



### Assign TAD and information to gene
gene.TSS.tb <- gene.TSS.tb %>% rowwise() %>%
  dplyr::mutate(TAD = findItsTAD(chr, TSS, tad))
#gene.TSS.tb <- gene.TSS.tb %>% dplyr::filter(!is.na(TAD))
temp <- tad.db %>% dplyr::select(-c(1, 2, 3))

gene.TSS.tb <- gene.TSS.tb %>% dplyr::left_join(temp, by = c("TAD" = "tadID"))

Plotting for groups

geneCount
Binary group
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.TSS.tb.plot <- gene.TSS.tb %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2", NA))) %>% 
  dplyr::filter(!is.na(group))


## geneCount
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$geneCount
  distance2 <- (data %>% dplyr::filter(group == group2) )$geneCount
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_geneCount <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = geneCount)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12)),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("geneCount_", note)
  height <- 3
  width <- 1.5
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_geneCount(gene.TSS.tb.plot, "group_binaryGroup", ymax = 200)
Group
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene


gene.TSS.tb.plot <- gene.TSS.tb %>% rowwise() %>% dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2",
                        ifelse(ensembl %in% group5, "group5",
                               ifelse(ensembl %in% group8, "group8", NA))))) %>% 
  dplyr::filter(!is.na(group))


## geneCount
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$geneCount
  distance2 <- (data %>% dplyr::filter(group == group2) )$geneCount
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_geneCount <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = geneCount)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("geneCount_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_geneCount(gene.TSS.tb.plot, "group", ymax = 200)
enhCount
Binary Group
## enhCount
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$enhCount
  distance2 <- (data %>% dplyr::filter(group == group2) )$enhCount
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_enhCount <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = enhCount)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12)),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("enhCount_", note)
  height <- 3
  width <- 1.5
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_enhCount(gene.TSS.tb.plot, "group_binaryGroup", ymax = 200)
Group
## enhCount
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$enhCount
  distance2 <- (data %>% dplyr::filter(group == group2) )$enhCount
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_enhCount <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = enhCount)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("enhCount_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_enhCount(gene.TSS.tb.plot, "group", ymax = 200)
geneDensity
binaryGroup
## geneDensity
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$geneDensity
  distance2 <- (data %>% dplyr::filter(group == group2) )$geneDensity
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_geneDensity <- function(temp.tb, note, ymin = 0, ymax = 10){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  
  p <- ggplot(temp.tb, aes(x = ".", fill = group, y = geneDensity)) +
    # Set axis labels (no x-axis title)
    labs(x = NULL, y = "Gene density within TAD") +
    scale_fill_manual(values = (rev(c("#777777","#F28E2C")))) +
    # Violin plot with black outline, customized line width and end
    introdataviz::geom_split_violin(linewidth = lineMedium * mmToLineUnit, lineend = "square",
                                    alpha = .4
    ) +
    
    # Box plot with customized line width, square end, and outlier size
    geom_boxplot(
      width = 0.3, color = "black",
      linewidth = lineMedium * mmToLineUnit, lineend = "square",
      outlier.shape = NA,  alpha = 0.6, show.legend = FALSE
    ) +
    
    # Mean point in each group
    stat_summary(
      aes(group = group), fun = mean,
      geom = "point", shape = 21, size = 0.5,
      fill = "black", color = "black", position = position_dodge(.3)
    ) +
    
    # Horizontal line at y = 0
    geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
    
    # Coordinate limits and custom y-axis labels
    coord_cartesian(ylim = c(ymin, ymax)) +
    
    # Annotate p-value text
    annotate(
      "text", x = 1, y = ymin + 1,
      label = paste0("p12: ", convPvalue(p12)),
      color = "black", hjust = 0, size = 3
    ) +
    
    # Theme customization
    theme_classic() +
    theme(
      axis.title = element_text(
        size = fontSizeM, family = fontType, color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeS, family = fontType, color = "#000000"
      ),
      axis.text.x = element_text(
        angle = 45, hjust = 1, vjust = 1
      ),
      axis.line = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
      legend.text = element_text(family = fontType, size = fontSizeS),
      legend.title = element_text(family = fontType, size = fontSizeS)
    )+   
    guides(
      fill = guide_legend(
        keywidth = 0.2,  # Adjust the width of the legend keys
        keyheight = 0.2  # Adjust the height of the legend keys
      ))
  
  
  
  
  
  fileName <- paste0("geneDensity_", note)
  width <- panelSize(1.5)*mmToInch
  height <- panelSize(1.2)*mmToInch
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_geneDensity(gene.TSS.tb.plot, "group_binaryGroup", ymax = 8)
Group
## geneDensity
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$geneDensity
  distance2 <- (data %>% dplyr::filter(group == group2) )$geneDensity
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_geneDensity <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = geneDensity)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("geneDensity_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_geneDensity(gene.TSS.tb.plot, "group", ymax = 10)
enhDensity
Binary group
## enhDensity
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$enhDensity
  distance2 <- (data %>% dplyr::filter(group == group2) )$enhDensity
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_enhDensity <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = enhDensity)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12)),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("enhDensity_", note)
  height <- 3
  width <- 1.5
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_enhDensity(gene.TSS.tb.plot, "group_binaryGroup", ymax = 10)
Group
## enhDensity
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$enhDensity
  distance2 <- (data %>% dplyr::filter(group == group2) )$enhDensity
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_enhDensity <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = enhDensity)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("enhDensity_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_enhDensity(gene.TSS.tb.plot, "group", ymax = 10)
regdensity
## regDensity
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$regDensity
  distance2 <- (data %>% dplyr::filter(group == group2) )$regDensity
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


plot_regDensity <- function(temp.tb, note, ymin = 0, ymax = 2000000){
  p12 <- round(getPvalWilcox(temp.tb, "group1", "group2"), 5)
  p15 <- round(getPvalWilcox(temp.tb, "group1", "group5"), 5)
  p18 <- round(getPvalWilcox(temp.tb, "group1", "group8"), 5)
  p25 <- round(getPvalWilcox(temp.tb, "group2", "group5"), 5)
  p28 <- round(getPvalWilcox(temp.tb, "group2", "group8"), 5)
  p58 <- round(getPvalWilcox(temp.tb, "group5", "group8"), 5)
  
  p <- ggplot(temp.tb, aes(x = group, y = regDensity)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() +
    annotate("text", x = 1, y = (ymin + ymax)/2 + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("regDensity_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}
plot_regDensity(gene.TSS.tb.plot, "group", ymax = 10)

Checking TAD average log2FC

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj)

temp <- left_join(gene.TSS.tb, diff.RNA, by = c("ensembl" = "ensembl_gene_id")) %>% dplyr::filter(!is.na(log2FoldChange),
                                                                                                  !is.na(TAD))


data <- temp %>% group_by(TAD) %>%
  dplyr::summarise(absAvgLog2FC = abs(mean(log2FoldChange)),
                   avgLog2FC = mean(log2FoldChange),
                   geneDensity = mean(geneDensity),
                   enhDensity = mean(enhDensity),
                   regDensity = mean(regDensity))

data$geneDensityGroup <- cut(
  data$geneDensity,
  breaks = quantile(data$geneDensity, probs = seq(0, 1, 0.2), na.rm = TRUE),
  include.lowest = TRUE,
  labels = paste0(seq(0, 80, 20), "-", seq(20, 100, 20), "%")
)

data$enhDensityGroup <- cut(
  data$enhDensity,
  breaks = quantile(data$enhDensity, probs = seq(0, 1, 0.2), na.rm = TRUE),
  include.lowest = TRUE,
  labels = paste0(seq(0, 80, 20), "-", seq(20, 100, 20), "%")
)


### Ploting  grouping

p <- ggplot(data, aes(x = enhDensityGroup, y = enhDensity, fill = enhDensityGroup)) + 
  geom_boxplot(color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  coord_cartesian(ylim = c(0, quantile(data$enhDensity, 0.99))) +
  labs(x = "Enhancer Density Group" , y = "TAD enhancer density") +
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) +
  theme(
    legend.position = "none",
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- paste0("tadGroup_enhDensity")
width <- panelSize(1.2)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()




p <- ggplot(data, aes(x = geneDensityGroup, y = geneDensity, fill = geneDensityGroup)) + 
  geom_boxplot(color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  coord_cartesian(ylim = c(0, quantile(data$geneDensity, 0.99))) +
  labs(x = "Gene Density Group" , y = "Gene density") +
  scale_fill_manual(values = c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C")) +
  theme(
    legend.position = "none",
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )
fileName <- paste0("tadGroup_geneDensity")
width <- 31*mmToInch
height <- 38*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


### Plotting distribution - enh
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(enhDensityGroup ==group1) )$avgLog2FC
  distance2 <- (data %>% dplyr::filter(enhDensityGroup ==group2) )$avgLog2FC
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


#### ALL
# ylim <- max(abs(quantile(data$avgLog2FC, 0.01)), abs(quantile(data$avgLog2FC, 0.99)))
# p <- ggplot(data, aes(x = enhDensityGroup, y = avgLog2FC)) + geom_violin(aes(fill = enhDensityGroup))+ 
#   geom_boxplot(outlier.shape = NA, width = 0.1) + theme_classic() +
#   coord_cartesian(ylim = c(-ylim, ylim)) +
#   geom_hline(yintercept = 0) +   theme(legend.position = "none") +
#   scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
# 
# fileName <- paste0("tadGroup_enhDensity_avgLog2FC")
# height <- 3
# width <- 3
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()
#### UP
data.plus <- data %>% dplyr::filter(avgLog2FC > 0)
ps01 <- round(getPvalWilcox(data.plus, "0-20%", "20-40%"), 5)
ps12 <- round(getPvalWilcox(data.plus, "20-40%", "40-60%"), 5)
ps23 <- round(getPvalWilcox(data.plus, "40-60%", "60-80%"), 5)
ps34 <- round(getPvalWilcox(data.plus, "60-80%", "80-100%"), 5)



p <- ggplot(data.plus, aes(x = enhDensityGroup, y = avgLog2FC)) + 
  geom_violin(aes(fill = enhDensityGroup),
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE)+ 
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  labs(x = "Enhancer density group" , y = "avg log2(fold change)") +
  stat_summary(
    aes(group = enhDensityGroup), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+ coord_cartesian(ylim = c(0, 1.5)) +
  annotate("text", x = 1, y = 1, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n"), 
           color = "black", hjust = 0, size = 2)


fileName <- paste0("tadGroup_enhDensity_avgLog2FC_up")
width <- panelSize(1.15)*mmToInch
height <- panelSize(1.07)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


#### DOWN
data.minus <- data %>% dplyr::filter(avgLog2FC < 0)
ps01 <- round(getPvalWilcox(data.minus, "0-20%", "20-40%"), 5)
ps12 <- round(getPvalWilcox(data.minus, "20-40%", "40-60%"), 5)
ps23 <- round(getPvalWilcox(data.minus, "40-60%", "60-80%"), 5)
ps34 <- round(getPvalWilcox(data.minus, "60-80%", "80-100%"), 5)


p <- ggplot(data.minus, aes(x = enhDensityGroup, y = avgLog2FC)) + 
  geom_violin(aes(fill = enhDensityGroup),
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE)+ 
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  labs(x = "Enhancer density group" , y = "avg log2(fold change)") +
  stat_summary(
    aes(group = enhDensityGroup), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+ coord_cartesian(ylim = c(-1.5, 0))+
  annotate("text", x = 1, y = -1, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n"), 
           color = "black", hjust = 0, size = 2)

fileName <- paste0("tadGroup_enhDensity_avgLog2FC_down")
width <- panelSize(1.175)*mmToInch
height <- panelSize(1.07)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



### Plotting distribution - gene
#### ALL
# ylim <- max(abs(quantile(data$avgLog2FC, 0.01)), abs(quantile(data$avgLog2FC, 0.99)))
# p <- ggplot(data, aes(x = geneDensityGroup, y = avgLog2FC)) + geom_violin(aes(fill = geneDensityGroup))+ 
#   geom_boxplot(outlier.shape = NA, width = 0.1) + theme_classic() +
#   coord_cartesian(ylim = c(-ylim, ylim)) +
#   geom_hline(yintercept = 0) +   theme(legend.position = "none") +
#   scale_fill_manual(values = c("#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252"))
# 
# fileName <- paste0("tadGroup_geneDensity_avgLog2FC")
# height <- 3
# width <- 3
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()
 getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(geneDensityGroup ==group1) )$avgLog2FC
  distance2 <- (data %>% dplyr::filter(geneDensityGroup ==group2) )$avgLog2FC
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


data.plus <- data %>% dplyr::filter(avgLog2FC > 0)
ps01 <- round(getPvalWilcox(data.plus, "0-20%", "20-40%"), 5)
ps12 <- round(getPvalWilcox(data.plus, "20-40%", "40-60%"), 5)
ps23 <- round(getPvalWilcox(data.plus, "40-60%", "60-80%"), 5)
ps34 <- round(getPvalWilcox(data.plus, "60-80%", "80-100%"), 5)



p <- ggplot(data.plus, aes(x = geneDensityGroup, y = avgLog2FC)) + 
  geom_violin(aes(fill = geneDensityGroup),
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE)+ 
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  labs(x = "Gene density group" , y = "avg log2(fold change)") +
  stat_summary(
    aes(group = geneDensityGroup), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+ coord_cartesian(ylim = c(0, 1.5)) +
  annotate("text", x = 1, y = 1, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n"), 
           color = "black", hjust = 0, size = 2)


fileName <- paste0("tadGroup_geneDensity_avgLog2FC_up")
width <- panelSize(1.15)*mmToInch
height <- panelSize(1.07)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


#### DOWN
data.minus <- data %>% dplyr::filter(avgLog2FC < 0)
ps01 <- round(getPvalWilcox(data.minus, "0-20%", "20-40%"), 5)
ps12 <- round(getPvalWilcox(data.minus, "20-40%", "40-60%"), 5)
ps23 <- round(getPvalWilcox(data.minus, "40-60%", "60-80%"), 5)
ps34 <- round(getPvalWilcox(data.minus, "60-80%", "80-100%"), 5)


p <- ggplot(data.minus, aes(x = geneDensityGroup, y = avgLog2FC)) + 
  geom_violin(aes(fill = geneDensityGroup),
              color = "black",
              linewidth = lineThick * mmToLineUnit, lineend = "square",
              show.legend = FALSE)+ 
  geom_boxplot(width = 0.1, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  labs(x = "Gene density group" , y = "avg log2(fold change)") +
  stat_summary(
    aes(group = geneDensityGroup), fun = mean,
    geom = "point", shape = 21, size = 1,
    fill = "red", color = "black"
  ) +
  scale_fill_manual(values = c("#D9D9D9", "#BFBFBF", "#A6A6A6", "#8C8C8C", "#737373")) +
  theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+ coord_cartesian(ylim = c(-1.5, 0))+
  annotate("text", x = 1, y = -1, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n"), 
           color = "black", hjust = 0, size = 2)

fileName <- paste0("tadGroup_geneDensity_avgLog2FC_down")
width <- panelSize(1.175)*mmToInch
height <- panelSize(1.07)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


### CDF plot

ks_result <- ks.test(
  data %>% dplyr::filter(geneDensityGroup == "0-20%") %>% pull(absAvgLog2FC),
  data %>% dplyr::filter(geneDensityGroup == "20-40%") %>% pull(absAvgLog2FC)
)


p <- ggplot(data, aes(x = absAvgLog2FC, color = geneDensityGroup)) +
  scale_color_manual(values = rev(c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))) +
  stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square" ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS),
    ) + scale_y_continuous(labels = scales::number_format(accuracy = 0.1))


fileName <- paste0("tadGroup_geneDensity_avgLog2FC_cdf")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

data <- data.minus

group1_data <- data$absAvgLog2FC[data$geneDensityGroup == "0-20%"]
group2_data <- data$absAvgLog2FC[data$geneDensityGroup == "20-40%"]
ks.test(group1_data, group2_data)

group1_data <- data$absAvgLog2FC[data$geneDensityGroup == "20-40%"]
group2_data <- data$absAvgLog2FC[data$geneDensityGroup == "40-60%"]
ks.test(group1_data, group2_data)

group1_data <- data$absAvgLog2FC[data$geneDensityGroup == "40-60%"]
group2_data <- data$absAvgLog2FC[data$geneDensityGroup == "60-80%"]
ks.test(group1_data, group2_data)

group1_data <- data$absAvgLog2FC[data$geneDensityGroup == "60-80%"]
group2_data <- data$absAvgLog2FC[data$geneDensityGroup == "80-100%"]
ks.test(group1_data, group2_data)

[2.18] Comparing TAD insulation score across samples

Checking how insulation score changes by treatment at DMSO TAD boundaries

name <- "chromo_cons_annoHierarchy"
consensus.loop.anno.tb <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import insulation score calculated with python
resultDir <- here("../../result")
insScore.DMSO <- fread(here(resultDir, "TAD", "insulationScore_25kb_G1DMSO.tsv")) %>% 
  dplyr::select(c("chrom", "start", "end", "log2_insulation_score_125000")) %>%
  dplyr::mutate(binID = paste(chrom, start, end, sep = "_"))
colnames(insScore.DMSO) <- c("chrom", "start", "end", "insulationScore", "binID")
insScore.dTAG <- fread(here(resultDir, "TAD", "insulationScore_25kb_G1dTAG.tsv")) %>% 
  dplyr::select(c("chrom", "start", "end", "log2_insulation_score_125000")) %>%
  dplyr::mutate(binID = paste(chrom, start, end, sep = "_"))
colnames(insScore.dTAG) <- c("chrom", "start", "end", "insulationScore", "binID")
insScore.A485 <- fread(here(resultDir, "TAD", "insulationScore_25kb_G1A485.tsv")) %>% 
  dplyr::select(c("chrom", "start", "end", "log2_insulation_score_125000")) %>%
  dplyr::mutate(binID = paste(chrom, start, end, sep = "_"))
colnames(insScore.A485) <- c("chrom", "start", "end", "insulationScore", "binID")

getInsulationScore <- function(chr, coordinate, insScore.tb){
  temp.tb <- insScore.tb %>% dplyr::filter(chrom == chr, start < coordinate, end > coordinate)
  out <- temp.tb$insulationScore
  if(length(out) < 1){
    return(NA)
  }else{
    return(temp.tb$insulationScore)
  }
}

# Importing TAD boundaries
tad_boundary <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_boundaries_G1DMSO.bed"))
colnames(tad_boundary) <- c("chr", "start", "end")
tad_boundary <- tad_boundary %>% rowwise() %>%
  dplyr::mutate(tad_id = paste(chr, start, end, sep = "_"),
                center = (start + end)/2,
                insScore_DMSO = getInsulationScore(chr, center, insScore.DMSO),
                insScore_dTAG = getInsulationScore(chr, center, insScore.dTAG),
                insScore_A485 = getInsulationScore(chr, center, insScore.A485))

tad_boundary <- tad_boundary %>% filter(!if_any(everything(), is.na))

tad_boundary$density <- get_density(tad_boundary$insScore_DMSO, tad_boundary$insScore_dTAG, n = 100)
tad_boundary <- tad_boundary %>% dplyr::arrange(density)
ggplot(tad_boundary, aes(x = insScore_DMSO, y = insScore_dTAG, color = density)) + 
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() + coord_fixed() +
  geom_abline(slope = 1, intercept = 0) + theme_bw()



tad_boundary$density <- get_density(tad_boundary$insScore_DMSO, tad_boundary$insScore_A485, n = 100)
tad_boundary <- tad_boundary %>% dplyr::arrange(density)
ggplot(tad_boundary, aes(x = insScore_DMSO, y = insScore_A485, color = density)) + 
  geom_point(show.legend = FALSE) + 
  scale_color_viridis() + coord_fixed() +
  geom_abline(slope = 1, intercept = 0) + theme_bw()

[2.20] Checking how many loops cross the boundary?

Previously, I tried to check the percentage of loops crossing the boundary per group which wasn’t fruitful. This time, try to do this on the differential loops. #### dTAG

### Importing differential regulatory loops

loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "UP/NO")
colnames(loop.up) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "UP/NO")
colnames(loop.no) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "DOWN")
colnames(loop.down) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")

loops <- bind_rows(bind_rows(loop.up, loop.no), loop.down)

### Importing TAD boundary
tad_boundary <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_boundaries_G1DMSO.bed"))
colnames(tad_boundary) <- c("chr", "start", "end")
tad_boundary <- tad_boundary %>% dplyr::mutate(tad_id = paste(chr, start, end, sep = "_"),
                                               start = start -175000/2,
                                               end = end + 175000/2,
                                               center = (start + end)/2)
### Functions
checkBoundaryCross <- function(chrom1, start1, end2, tad_boundary){
  temp <- tad_boundary %>% dplyr::filter(chr == chrom1,
                                 center > start1,
                                 center < end2)
  return(length(temp$center))
}

### Check overlap
loops <- loops %>% rowwise() %>%
  dplyr::mutate(boundaryCross = checkBoundaryCross(chr1, start1, end2, tad_boundary))

### Plotting
summary_data <- loops %>%
  group_by(group) %>%
  summarise(percentage = mean(boundaryCross > 0) * 100)

summary_data$group <- factor(summary_data$group, levels = c("UP/NO", "DOWN"))

p <- ggplot(summary_data, aes(x = group, y = percentage)) +
  geom_bar(stat = "identity", fill = darken(strong_green, amount = 0.2)) +
  labs(y = "% of loops crossing TAD boundary", x = NULL) +
  theme_classic() + ylim(0, 100) +
  theme(
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
  )

fileName <- paste0("boundaryCrossRatio")
width <- panelSize(1)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

A485

### Importing differential regulatory loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "up")
colnames(loop.up) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "no")
colnames(loop.no) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe")) %>%
  dplyr::mutate(group = "down")
colnames(loop.down) <- c("chr1", "start1", "end1", "chr2", "start2", "end2", "group")

loops <- bind_rows(bind_rows(loop.up, loop.no), loop.down)

### Importing TAD boundary
tad_boundary <- fread(here("../../result/TAD", "TAD_25kb_125kb_otsu_boundaries_G1DMSO.bed"))
colnames(tad_boundary) <- c("chr", "start", "end")
tad_boundary <- tad_boundary %>% dplyr::mutate(tad_id = paste(chr, start, end, sep = "_"),
                                               start = start -175000/2,
                                               end = end + 175000/2,
                                               center = (start + end)/2)
### Functions
checkBoundaryCross <- function(chrom1, start1, end2, tad_boundary){
  temp <- tad_boundary %>% dplyr::filter(chr == chrom1,
                                 center > start1,
                                 center < end2)
  return(length(temp$center))
}

### Check overlap
loops <- loops %>% rowwise() %>%
  dplyr::mutate(boundaryCross = checkBoundaryCross(chr1, start1, end2, tad_boundary))

### Plotting
summary_data <- loops %>%
  group_by(group) %>%
  summarise(percentage = mean(boundaryCross > 0) * 100)


p <- ggplot(summary_data, aes(x = group, y = percentage)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Percentage of Rows with boundaryCross > 0 per Group",
       x = "Group",
       y = "Percentage") +
  theme_classic() + ylim(0, 100)

fileName <- paste0("boundaryCrossRatio_A485")
height <- 3
width <- 3
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[2.21] LOLA on differential loop anchors

LOADING LOLA
# LOADING LOLA DB
library("simpleCache")
library("LOLA")
lolaDB = loadRegionDB("/Volumes/UKJIN_SSD/Genomics_03_Analysis_Working/reference/LOLACore_cached/mm10")

# FUNCTIONS
extractAnchor <- function(loop){
  anchor1 <- loop %>% dplyr::select(c(1, 2, 3))
  colnames(anchor1) <- c("chr", "start", "end")
  anchor2 <- loop %>% dplyr::select(c(4, 5, 6))
  colnames(anchor2) <- c("chr", "start", "end")
  anchors <- reduce(makeGRangesFromDataFrame(bind_rows(anchor1, anchor2)))
    return(anchors)
}

dTAG, Comparing to Async

- Limited to ATAC-seq signal, reg loop backgroupd
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])



loop.1 <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_bothRetained.bedpe"))
anchor.1 <- (extractAnchor(loop.1))
overlaps <- findOverlaps(anchor.1, atac.gr)
anchor.1 <- pintersect(anchor.1[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.2 <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_AsyncSpecificPert.bedpe"))
anchor.2 <- (extractAnchor(loop.2))
overlaps <- findOverlaps(anchor.2, atac.gr)
anchor.2 <- pintersect(anchor.2[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.3 <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_G1SpecificPert.bedpe"))
anchor.3 <- (extractAnchor(loop.3))
overlaps <- findOverlaps(anchor.3, atac.gr)
anchor.3 <- pintersect(anchor.3[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.4 <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_G1vsAsync_bothPert.bedpe"))
anchor.4 <- (extractAnchor(loop.4))
overlaps <- findOverlaps(anchor.4, atac.gr)
anchor.4 <- pintersect(anchor.4[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


anchors <- list(anchor.1, anchor.2, anchor.3, anchor.4)
tbs <- list()
temps <- list()

# Process clusters c1 to c8
for (i in 1:4) {
  
  anchor <- anchors[[i]]
  # Run LOLA
  result <- runLOLA(anchor, anchor.all, lolaDB)
  tb <- as_tibble(result)
  
  # Filter and summarize
  tb <- tb %>%
    dplyr::mutate(target = toupper(antibody)) %>%
    filter(str_to_lower(cellType) == "embryonic stem cell") %>%
    dplyr::filter(qValue < alpha) %>%
    dplyr::group_by(target) %>%
    slice_min(meanRnk, with_ties = FALSE)
  
  # Store tb
  tbs[[i]] <- tb
  
  # Select and rename oddsRatio
  temp <- tb %>% dplyr::select(target, oddsRatio)
  colnames(temp) <- c("target", paste0("OR_c", i))
  
  # Store temp
  temps[[i]] <- temp
}

# Merge all temp tables into one
temp <- Reduce(function(x, y) full_join(x, y, by = "target"), temps) %>%
  mutate_all(~replace_na(., 1))
colnames(temp) <- c("target", "bothRetained", "AsyncSpecificPerturb", "G1SpecificPerturb", "bothPerturb")
data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

dTAG

- Limiting to ATAC-seq signal, reg loop background
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.upno <- bind_rows(loop.up, loop.no)
anchor.upno <- (extractAnchor(loop.upno))
overlaps <- findOverlaps(anchor.upno, atac.gr)
anchor.upno <- pintersect(anchor.upno[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_atac.tsv"), sep = "\t")

# UPNO
result = runLOLA(anchor.upno, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_atac.tsv"), sep = "\t")

# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_atac.tsv"), sep = "\t")


### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

# p <- Heatmap(
#   data,
#   name = "Odds Ratio",                   # Name of the heatmap legend
#   cluster_columns = FALSE,            # Remove column dendrogram
#   row_km = 4,                         # Define the number of k-means clusters for rows (adjust as needed)
#   show_row_dend = FALSE,
#   col = col_fun                       # Use the red gradient color scale
# )
# 
# fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_regAnchorBackground_atac")
# height <- 7
# width <- 3.5
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()
# 


### Visualizing p-value and OR
alpha <- 0.05
# tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "UP") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
# tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "NO") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)

tb.upno <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log10(qValue),
                group = "UP/NO") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
fwrite(tb.upno %>% dplyr::select(c(24, 16, 20,
                                   4, 25, 5,
                                   7, 8, 9, 10, 11,
                                   12, 13, 14)), here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_atac_pub.tsv"), sep = "\t")

tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log10(qValue),
                group = "DOWN") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
fwrite(tb.down %>% dplyr::select(c(24, 16, 20,
                                   4, 25, 5,
                                   7, 8, 9, 10, 11,
                                   12, 13, 14)), here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_atac_pub.tsv"), sep = "\t")


temp.upno <- tb.upno %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)

temp <- bind_rows(temp.upno, temp.down)

# order <- c((temp %>% dplyr::filter(group == "UP/NO") %>% arrange(desc(oddsRatio)))$target, 
#            (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target)

# temp$target <- factor(temp$target, levels = rev(order))
temp$group <- factor(temp$group, levels = c("UP/NO", "DOWN"))

targetList <- c("POLR2A", "CTR9",
                "AFF4", "ELL2",
                "MED1", "MED12",
                "TBP", "TAF1", "TAF3",
                "E2F1", "YY1", "NIPBL", 
                "EP300", "DPY30", "SETDB1",
                "RAD21", "SMC1A", "SMC3", "CTCF",
                "SUZ12", "PHF19"
)
temp <- temp %>% dplyr::filter(target %in% targetList)
temp$target <- factor(temp$target, levels = rev(targetList))


qValueLogMax <- 50
temp2 <- temp %>% dplyr::mutate(qValueLog = min(qValueLog, qValueLogMax))

p <- ggplot(temp2, aes(x = group, y = target, fill = oddsRatio, size = qValueLog)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )
# p <- ggplot(temp, aes(x = group, y = target, color = qValueLog, size = oddsRatio)) +
#   geom_point() + theme_bw() + 
#   scale_size_continuous(range = c(1, 3)) +  # Set min and max point sizes here
#   scale_color_gradient(low = "blue", high = "red",
#                        guide = guide_colorbar(
#                          barwidth = 1.5/5.08,  # Adjust width of the color bar
#                          barheight = 15/5.08    # Adjust height of the color bar
#                        )) +
#   labs(x = NULL, y = NULL)  +
#   theme(
#     axis.title = element_text(
#       size = fontSizeS,
#       family = fontType,
#       color = "#000000"
#     ),
#     axis.text = element_text(
#       size = fontSizeS,
#       family = fontType,
#       color = "#000000"
#     ),
#     axis.text.x = element_text(
#       angle = 45,      # Rotate x-axis labels 45 degrees
#       hjust = 1,       # Adjust horizontal justification
#       vjust = 1        # Adjust vertical justification
#     ),
#     axis.line = element_line(
#       color = "#000000",
#       size = lineThick*mmToLineUnit,
#       lineend = "square"
#     ),
#     axis.ticks = element_line(
#       color = "#000000",
#       size = lineThick*mmToLineUnit,
#       lineend = "square"
#     ),
#     panel.background = element_rect(fill = "transparent"),
#     legend.text = element_text(family = fontType, size = fontSizeS),
#     legend.title = element_text(family = fontType, size = fontSizeS)
#   )

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_OR_qValue_regAnchorBackground_atac_upno")
width <- panelSize(1.5)*mmToInch
height <- panelSize(1.9)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
### 241015 Testing on subset of loops
anchor.c1 <- extractAnchor(loop.cluster1)
overlaps <- findOverlaps(anchor.c1, atac.gr)
anchor.c1 <- pintersect(anchor.c1[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c2 <- extractAnchor(loop.cluster2)
overlaps <- findOverlaps(anchor.c2, atac.gr)
anchor.c2 <- pintersect(anchor.c2[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c3 <- extractAnchor(loop.cluster3)
overlaps <- findOverlaps(anchor.c3, atac.gr)
anchor.c3 <- pintersect(anchor.c3[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c4 <- extractAnchor(loop.cluster4)
overlaps <- findOverlaps(anchor.c4, atac.gr)
anchor.c4 <- pintersect(anchor.c4[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c5 <- extractAnchor(loop.cluster5)
overlaps <- findOverlaps(anchor.c5, atac.gr)
anchor.c5 <- pintersect(anchor.c5[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c6 <- extractAnchor(loop.cluster6)
overlaps <- findOverlaps(anchor.c6, atac.gr)
anchor.c6 <- pintersect(anchor.c6[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c7 <- extractAnchor(loop.cluster7)
overlaps <- findOverlaps(anchor.c7, atac.gr)
anchor.c7 <- pintersect(anchor.c7[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c8 <- extractAnchor(loop.cluster8)
overlaps <- findOverlaps(anchor.c8, atac.gr)
anchor.c8 <- pintersect(anchor.c8[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

result = runLOLA(anchor.c1, anchor.all, lolaDB)
tb.c1 = as_tibble(result)

result = runLOLA(anchor.c2, anchor.all, lolaDB)
tb.c2 = as_tibble(result)

result = runLOLA(anchor.c3, anchor.all, lolaDB)
tb.c3 = as_tibble(result)

result = runLOLA(anchor.c4, anchor.all, lolaDB)
tb.c4 = as_tibble(result)
result = runLOLA(anchor.c5, anchor.all, lolaDB)
tb.c5 = as_tibble(result)

result = runLOLA(anchor.c6, anchor.all, lolaDB)
tb.c6 = as_tibble(result)

result = runLOLA(anchor.c7, anchor.all, lolaDB)
tb.c7 = as_tibble(result)

result = runLOLA(anchor.c8, anchor.all, lolaDB)
tb.c8 = as_tibble(result)

### HEATMAP
alpha <- 0.05
tb.c1 <- tb.c1 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c2 <- tb.c2 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c3 <- tb.c3 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c4 <- tb.c4 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c5 <- tb.c5 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c6 <- tb.c6 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c7 <- tb.c7 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c8 <- tb.c8 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.c1 <- tb.c1 %>% dplyr::select(target, oddsRatio)
colnames(temp.c1) <- c("target", "OR_c1")
temp.c2 <- tb.c2 %>% dplyr::select(target, oddsRatio)
colnames(temp.c2) <- c("target", "OR_c2")
temp.c3 <- tb.c3 %>% dplyr::select(target, oddsRatio)
colnames(temp.c3) <- c("target", "OR_c3")
temp.c4 <- tb.c4 %>% dplyr::select(target, oddsRatio)
colnames(temp.c4) <- c("target", "OR_c4")
temp.c5 <- tb.c5 %>% dplyr::select(target, oddsRatio)
colnames(temp.c5) <- c("target", "OR_c5")
temp.c6 <- tb.c6 %>% dplyr::select(target, oddsRatio)
colnames(temp.c6) <- c("target", "OR_c6")
temp.c7 <- tb.c7 %>% dplyr::select(target, oddsRatio)
colnames(temp.c7) <- c("target", "OR_c7")
temp.c8 <- tb.c8 %>% dplyr::select(target, oddsRatio)
colnames(temp.c8) <- c("target", "OR_c8")

temp <- full_join(temp.c1, temp.c2, by = "target") %>%
  full_join(temp.c3, by = "target") %>%
  full_join(temp.c4, by = "target") %>%
  full_join(temp.c5, by = "target") %>%
  full_join(temp.c6, by = "target") %>%
  full_join(temp.c7, by = "target") %>%
  full_join(temp.c8, by = "target") %>%
  mutate_all(~replace_na(., 1))

data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)


# Initialize lists to store results
anchors <- list()
tbs <- list()
temps <- list()

# Process clusters c1 to c8
for (i in 1:4) {
  # Extract anchor
  loop_cluster <- get(paste0("loop.cluster", i))
  anchor <- extractAnchor(loop_cluster)
  
  # Find overlaps and intersect
  overlaps <- findOverlaps(anchor, atac.gr)
  anchor <- pintersect(anchor[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
  
  # Store anchor
  anchors[[i]] <- anchor
  
  # Run LOLA
  result <- runLOLA(anchor, anchor.all, lolaDB)
  tb <- as_tibble(result)
  
  # Filter and summarize
  tb <- tb %>%
    dplyr::mutate(target = toupper(antibody)) %>%
    filter(str_to_lower(cellType) == "embryonic stem cell") %>%
    dplyr::filter(qValue < alpha) %>%
    dplyr::group_by(target) %>%
    slice_min(meanRnk, with_ties = FALSE)
  
  # Store tb
  tbs[[i]] <- tb
  
  # Select and rename oddsRatio
  temp <- tb %>% dplyr::select(target, oddsRatio)
  colnames(temp) <- c("target", paste0("OR_c", i))
  
  # Store temp
  temps[[i]] <- temp
}

# Merge all temp tables into one
temp <- Reduce(function(x, y) full_join(x, y, by = "target"), temps) %>%
  mutate_all(~replace_na(., 1))
data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)
- Limited to ATAC-seq signal, all loop backgroup
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.upno <- bind_rows(loop.up, loop.no)
anchor.upno <- (extractAnchor(loop.upno))
overlaps <- findOverlaps(anchor.upno, atac.gr)
anchor.upno <- pintersect(anchor.upno[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


loopNum <- nrow(loop.upno)

# Selecting same number of extreme down loops
loop.down <- loop.all %>% dplyr::filter(diff_dTAG_DMSO < -0.2) %>% dplyr::arrange(diff_dTAG_DMSO) %>% slice_head(n = loopNum)
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
#fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
#fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv"), sep = "\t")

# UPNO
result = runLOLA(anchor.upno, anchor.all, lolaDB)
tb = as_tibble(result)
#fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_allLoops_extreme_atac.tsv"), sep = "\t")


# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
#fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv"), sep = "\t")



### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

# p <- Heatmap(
#   data,
#   name = "Odds Ratio",                   # Name of the heatmap legend
#   cluster_columns = FALSE,            # Remove column dendrogram
#   row_km = 10,                         # Define the number of k-means clusters for rows (adjust as needed)
#   show_row_dend = FALSE,
#   col = col_fun,
#   border = TRUE
# )
# 
# fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_allLoops_extreme_allAnchorBackground_atac")
# height <- 7
# width <- 3.5
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()




### Visualizing p-value and OR
alpha <- 0.05
# tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "UP") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
# tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "NO") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
tb.upno <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log10(qValue),
                group = "UP/NO") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
fwrite(tb.upno %>% dplyr::select(c(24, 16, 20,
                                   4, 25, 5,
                                   7, 8, 9, 10, 11,
                                   12, 13, 14)), here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_upno_allLoops_extreme_atac_pub.tsv"), sep = "\t")
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log10(qValue),
                group = "DOWN") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
fwrite(tb.down %>% dplyr::select(c(24, 16, 20,
                                   4, 25, 5,
                                   7, 8, 9, 10, 11,
                                   12, 13, 14)), here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_allLoops_extreme_atac_pub.tsv"), sep = "\t")

# temp.up <- tb.up %>% dplyr::select(target, oddsRatio, qValueLog, group)
# temp.no <- tb.no %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.upno <- tb.upno %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)

temp <- bind_rows(temp.upno, temp.down)
# 
# order <- c((temp %>% dplyr::filter(group == "UP/NO") %>% arrange(desc(oddsRatio)))$target, 
#            (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target)
# temp$target <- factor(temp$target, levels = rev(order))
temp$group <- factor(temp$group, levels = c("UP/NO", "DOWN"))


targetList <- c("POLR2A", "CTR9",
                "AFF4", "ELL2",
                "MED1", "MED12",
                "TBP", "TAF1", "TAF3",
                "ESRRB", "KLF4", "NANOG", "POU5F1", "SOX2", "STAT3", "E2F1", "YY1",
                "EP300", "DPY30", "EZH2", "KDM2B", "KDB4B", "KDM4C", "KDM6B", "RBBP5",
                "RAD21", "SMC1A", "SMC3", "CTCF",
                "JARID2", "SUZ12"
)
temp <- temp %>% dplyr::filter(target %in% targetList)

temp$target <- factor(temp$target, levels = rev(targetList))
# MAX qValueLog to 50
qValueLogMax <- 50
temp2 <- temp %>% dplyr::mutate(qValueLog = min(qValueLog, qValueLogMax))
p <- ggplot(temp2, aes(x = group, y = target, fill = oddsRatio, size = qValueLog)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 0.5*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(0.5, 2)) +  # Set min and max point sizes here
  scale_fill_gradient(low = "white", high = "#CB333A",
                      limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + 
  labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_allLoops_extreme_OR_qValue_allAnchorBackground_atac_ordered")
width <- panelSize(1.5)*mmToInch
height <- panelSize(2.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

dTAG, obsexp

- Limited to ATAC-seq signal, all loop backgroup
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_all_dTAGvsDMSO_UP_diff0.5.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_all_dTAGvsDMSO_NO_diff0.5.bedpe"))
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_all_dTAGvsDMSO_DOWN_diff0.5.bedpe"))
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_up_allLoops_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_no_allLoops_atac.tsv"), sep = "\t")

# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_down_allLoops_atac.tsv"), sep = "\t")



### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_up_allLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_no_allLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_down_allLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  row_km = 4,                        # Define the number of k-means clusters for rows (adjust as needed)
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_logOE_diff0.5_allLoops_allAnchorBackground_atac")
height <- 7
width <- 3.5
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


############
# 
# ### Visualizing p-value and OR
# alpha <- 0.05
# tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_up_allLoops_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "UP") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
# tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_no_allLoops_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "NO") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
# tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_down_allLoops_atac.tsv")) %>%
#   dplyr::mutate(target = toupper(antibody),
#                 qValueLog = -log2(qValue),
#                 group = "DOWN") %>%
#   filter(str_to_lower(cellType) == "embryonic stem cell") %>%
#   dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
#   slice_min(meanRnk, with_ties = FALSE)
# 
# temp.up <- tb.up %>% dplyr::select(target, oddsRatio, qValueLog, group)
# temp.no <- tb.no %>% dplyr::select(target, oddsRatio, qValueLog, group)
# temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)
# 
# temp <- bind_rows(temp.up, temp.down)
# 
# order <- c((temp %>% dplyr::filter(group == "UP") %>% arrange(desc(oddsRatio)))$target, 
#            (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target)
# temp$target <- factor(temp$target, levels = rev(order))
# p <- ggplot(temp, aes(x = group, y = target, color = qValueLog, size = oddsRatio)) +
#   geom_point() + theme_bw() + scale_color_gradient(low = "blue", high = "red") +
#   labs(x = NULL, y = NULL)  +   scale_size_continuous(range = c(1, 3)) +
#   theme(axis.text = element_text(size = 6),  # Set axis text size
#         axis.title = element_text(size = 6), # Set axis title size (if not removed)
#         legend.text = element_text(size = 6), # Set legend text size
#         legend.title = element_text(size = 6)) 
# 
# fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_logOE_diff0.5_allLoops_OR_allAnchorBackground_atac")
# height <-3
# width <- 2
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
# svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
# print(p)
# dev.off()
- Limiting to ATAC-seq signal, reg loop background
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_pe-pe_dTAGvsDMSO_UP_diff0.5.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_pe-pe_dTAGvsDMSO_NO_diff0.5.bedpe"))
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])


loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_logOE_pe-pe_dTAGvsDMSO_DOWN_diff0.5.bedpe"))
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_up_pe-peLoops_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_no_pe-peLoops_atac.tsv"), sep = "\t")

# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_down_pe-peLoops_atac.tsv"), sep = "\t")


### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_up_pe-peLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_no_pe-peLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_logOE_diff0.5_down_pe-peLoops_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  row_km = 4,                         # Define the number of k-means clusters for rows (adjust as needed)
  show_row_dend = FALSE,
  col = col_fun                       # Use the red gradient color scale
)

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_logOE_diff0.5_pe-peLoops_regAnchorBackground_atac")
height <- 7
width <- 3.5
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



### Visualizing p-value and OR
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_up_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "UP") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_no_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "NO") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_dTAG_vs_DMSO_diff0.2_down_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "DOWN") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.no <- tb.no %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)

temp <- bind_rows(temp.up, temp.down)

order <- c((temp %>% dplyr::filter(group == "UP") %>% arrange(desc(oddsRatio)))$target, 
           (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target)
temp$target <- factor(temp$target, levels = rev(order))
p <- ggplot(temp, aes(x = group, y = target, color = qValueLog, size = oddsRatio)) +
  geom_point() + theme_bw() + scale_color_gradient(low = "blue", high = "red") +
  labs(x = NULL, y = NULL)  +
  theme(axis.text = element_text(size = 6),  # Set axis text size
        axis.title = element_text(size = 6), # Set axis title size (if not removed)
        legend.text = element_text(size = 6), # Set legend text size
        legend.title = element_text(size = 6)) 

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_OR_qValue_regAnchorBackground_atac")
height <-3
width <- 2
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()





### 241015 Testing on subset of loops
anchor.c1 <- extractAnchor(loop.cluster1)
overlaps <- findOverlaps(anchor.c1, atac.gr)
anchor.c1 <- pintersect(anchor.c1[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c2 <- extractAnchor(loop.cluster2)
overlaps <- findOverlaps(anchor.c2, atac.gr)
anchor.c2 <- pintersect(anchor.c2[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c3 <- extractAnchor(loop.cluster3)
overlaps <- findOverlaps(anchor.c3, atac.gr)
anchor.c3 <- pintersect(anchor.c3[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c4 <- extractAnchor(loop.cluster4)
overlaps <- findOverlaps(anchor.c4, atac.gr)
anchor.c4 <- pintersect(anchor.c4[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c5 <- extractAnchor(loop.cluster5)
overlaps <- findOverlaps(anchor.c5, atac.gr)
anchor.c5 <- pintersect(anchor.c5[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c6 <- extractAnchor(loop.cluster6)
overlaps <- findOverlaps(anchor.c6, atac.gr)
anchor.c6 <- pintersect(anchor.c6[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c7 <- extractAnchor(loop.cluster7)
overlaps <- findOverlaps(anchor.c7, atac.gr)
anchor.c7 <- pintersect(anchor.c7[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

anchor.c8 <- extractAnchor(loop.cluster8)
overlaps <- findOverlaps(anchor.c8, atac.gr)
anchor.c8 <- pintersect(anchor.c8[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

result = runLOLA(anchor.c1, anchor.all, lolaDB)
tb.c1 = as_tibble(result)

result = runLOLA(anchor.c2, anchor.all, lolaDB)
tb.c2 = as_tibble(result)

result = runLOLA(anchor.c3, anchor.all, lolaDB)
tb.c3 = as_tibble(result)

result = runLOLA(anchor.c4, anchor.all, lolaDB)
tb.c4 = as_tibble(result)
result = runLOLA(anchor.c5, anchor.all, lolaDB)
tb.c5 = as_tibble(result)

result = runLOLA(anchor.c6, anchor.all, lolaDB)
tb.c6 = as_tibble(result)

result = runLOLA(anchor.c7, anchor.all, lolaDB)
tb.c7 = as_tibble(result)

result = runLOLA(anchor.c8, anchor.all, lolaDB)
tb.c8 = as_tibble(result)

### HEATMAP
alpha <- 0.05
tb.c1 <- tb.c1 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c2 <- tb.c2 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c3 <- tb.c3 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c4 <- tb.c4 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.c5 <- tb.c5 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c6 <- tb.c6 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c7 <- tb.c7 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

tb.c8 <- tb.c8 %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>%
  dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.c1 <- tb.c1 %>% dplyr::select(target, oddsRatio)
colnames(temp.c1) <- c("target", "OR_c1")
temp.c2 <- tb.c2 %>% dplyr::select(target, oddsRatio)
colnames(temp.c2) <- c("target", "OR_c2")
temp.c3 <- tb.c3 %>% dplyr::select(target, oddsRatio)
colnames(temp.c3) <- c("target", "OR_c3")
temp.c4 <- tb.c4 %>% dplyr::select(target, oddsRatio)
colnames(temp.c4) <- c("target", "OR_c4")
temp.c5 <- tb.c5 %>% dplyr::select(target, oddsRatio)
colnames(temp.c5) <- c("target", "OR_c5")
temp.c6 <- tb.c6 %>% dplyr::select(target, oddsRatio)
colnames(temp.c6) <- c("target", "OR_c6")
temp.c7 <- tb.c7 %>% dplyr::select(target, oddsRatio)
colnames(temp.c7) <- c("target", "OR_c7")
temp.c8 <- tb.c8 %>% dplyr::select(target, oddsRatio)
colnames(temp.c8) <- c("target", "OR_c8")

temp <- full_join(temp.c1, temp.c2, by = "target") %>%
  full_join(temp.c3, by = "target") %>%
  full_join(temp.c4, by = "target") %>%
  full_join(temp.c5, by = "target") %>%
  full_join(temp.c6, by = "target") %>%
  full_join(temp.c7, by = "target") %>%
  full_join(temp.c8, by = "target") %>%
  mutate_all(~replace_na(., 1))

data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)


# Initialize lists to store results
anchors <- list()
tbs <- list()
temps <- list()

# Process clusters c1 to c8
for (i in 1:4) {
  # Extract anchor
  loop_cluster <- get(paste0("loop.cluster", i))
  anchor <- extractAnchor(loop_cluster)
  
  # Find overlaps and intersect
  overlaps <- findOverlaps(anchor, atac.gr)
  anchor <- pintersect(anchor[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
  
  # Store anchor
  anchors[[i]] <- anchor
  
  # Run LOLA
  result <- runLOLA(anchor, anchor.all, lolaDB)
  tb <- as_tibble(result)
  
  # Filter and summarize
  tb <- tb %>%
    dplyr::mutate(target = toupper(antibody)) %>%
    filter(str_to_lower(cellType) == "embryonic stem cell") %>%
    dplyr::filter(qValue < alpha) %>%
    dplyr::group_by(target) %>%
    slice_min(meanRnk, with_ties = FALSE)
  
  # Store tb
  tbs[[i]] <- tb
  
  # Select and rename oddsRatio
  temp <- tb %>% dplyr::select(target, oddsRatio)
  colnames(temp) <- c("target", paste0("OR_c", i))
  
  # Store temp
  temps[[i]] <- temp
}

# Merge all temp tables into one
temp <- Reduce(function(x, y) full_join(x, y, by = "target"), temps) %>%
  mutate_all(~replace_na(., 1))
data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

A485

- Limited to ATAC-seq signal, all loop backgroupd
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loopNum <- nrow(loop.down)

# Selecting same number of extreme no loops
loop.no <- loop.all %>% 
  dplyr::mutate(absDiff = abs(diff_A485_DMSO)) %>%
  dplyr::filter(absDiff < 0.2) %>%
  dplyr::arrange(absDiff) %>% slice_head(n = loopNum)
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv"), sep = "\t")

# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv"), sep = "\t")



### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  row_km = 5,                         # Define the number of k-means clusters for rows (adjust as needed)
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

fileName <- paste0("anchorLOLA_A485_vs_DMSO_diff0.2_allLoops_extreme_regAnchorBackground_atac")
height <- 7
width <- 3.5
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()




### Visualizing p-value and OR
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "UP") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "NO") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_allLoops_extreme_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "DOWN") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.no <- tb.no %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)

temp <- bind_rows(temp.up, temp.down)

order <- unique(c((temp %>% dplyr::filter(group == "UP") %>% arrange(desc(oddsRatio)))$target, 
           (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target))
temp$target <- factor(temp$target, levels = rev(order))
p <- ggplot(temp, aes(x = group, y = target, color = qValueLog, size = oddsRatio)) +
  geom_point() + theme_bw() + scale_color_gradient(low = "blue", high = "red") +
  labs(x = NULL, y = NULL)  +   scale_size_continuous(range = c(1, 3)) +
  theme(axis.text = element_text(size = 6),  # Set axis text size
        axis.title = element_text(size = 6), # Set axis title size (if not removed)
        legend.text = element_text(size = 6), # Set legend text size
        legend.title = element_text(size = 6)) 

fileName <- paste0("anchorLOLA_A485_vs_DMSO_diff0.2_allLoops_extreme_OR_qValue_regAnchorBackground_atac")
height <-3
width <- 2
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
- Limited to ATAC-seq signal, reg loop backgrouund
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
### Importing differential regulatory loops & extract anchor
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
overlaps <- findOverlaps(anchor.up, atac.gr)
anchor.up <- pintersect(anchor.up[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
overlaps <- findOverlaps(anchor.no, atac.gr)
anchor.no <- pintersect(anchor.no[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))
overlaps <- findOverlaps(anchor.down, atac.gr)
anchor.down <- pintersect(anchor.down[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
# RUNNING LOLA
lolaDir <- here("../../result/lola")
dir.create(lolaDir, showWarnings = FALSE, recursive = TRUE)

# UP
result = runLOLA(anchor.up, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_atac.tsv"), sep = "\t")

# NO
result = runLOLA(anchor.no, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_atac.tsv"), sep = "\t")

# DOWN
result = runLOLA(anchor.down, anchor.all, lolaDB)
tb = as_tibble(result)
fwrite(tb, here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_atac.tsv"), sep = "\t")



### HEATMAP
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody)) %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio)
colnames(temp.up) <- c("target", "OR_up")
temp.no <- tb.no %>% dplyr::select(target, oddsRatio)
colnames(temp.no) <- c("target", "OR_no")
temp.down <- tb.down %>% dplyr::select(target, oddsRatio)
colnames(temp.down) <- c("target", "OR_down")


temp <- full_join(full_join(temp.up, temp.no, by = c("target")), temp.down, by = c("target")) %>% mutate_all(~replace_na(., 1))

data <- as.matrix(temp[2:4])
rownames(data) <- temp$target

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  row_km = 4,                         # Define the number of k-means clusters for rows (adjust as needed)
  show_row_dend = FALSE,
  col = col_fun                       # Use the red gradient color scale
)

fileName <- paste0("anchorLOLA_A485_vs_DMSO_diff0.2_regAnchorBackground_atac")
height <- 7
width <- 3.5
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()


### Visualizing p-value and OR
alpha <- 0.05
tb.up <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_up_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "UP") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.no <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_no_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "NO") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)
tb.down <- fread(here(lolaDir, "LOLA_A485_vs_DMSO_diff0.2_down_atac.tsv")) %>%
  dplyr::mutate(target = toupper(antibody),
                qValueLog = -log2(qValue),
                group = "DOWN") %>%
  filter(str_to_lower(cellType) == "embryonic stem cell") %>%
  dplyr::filter(qValue < alpha) %>% dplyr::group_by(target) %>%
  slice_min(meanRnk, with_ties = FALSE)

temp.up <- tb.up %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.no <- tb.no %>% dplyr::select(target, oddsRatio, qValueLog, group)
temp.down <- tb.down %>% dplyr::select(target, oddsRatio, qValueLog, group)

temp <- bind_rows(temp.up, temp.down)

order <- c((temp %>% dplyr::filter(group == "UP") %>% arrange(desc(oddsRatio)))$target, 
           (temp %>% dplyr::filter(group == "DOWN") %>% arrange(desc(oddsRatio)))$target)
temp$target <- factor(temp$target, levels = rev(order))
p <- ggplot(temp, aes(x = group, y = target, color = qValueLog, size = oddsRatio)) +
  geom_point() + theme_bw() + scale_color_gradient(low = "blue", high = "red") +
  labs(x = NULL, y = NULL)  +
  theme(axis.text = element_text(size = 6),  # Set axis text size
        axis.title = element_text(size = 6), # Set axis title size (if not removed)
        legend.text = element_text(size = 6), # Set legend text size
        legend.title = element_text(size = 6)) 

fileName <- paste0("anchorLOLA_A485_vs_DMSO_diff0.2_OR_qValue_regAnchorBackground_atac")
height <-3
width <- 2
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[2.22] Comparing absolute RNA expression level across group

The aim is to see if there is a trend in RNA expression level among group 1, 2, 3, 4. It would be making comparison among genes. For this, TPM should be used.

## Importing groups
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene

## Importing RNA-seq TPM for DMSO
tpm.selected <- fread(here(refDir, "readCount.filtered.TPM.all.tsv")) %>% dplyr::select(1, 3, 4, 5)
colnames(tpm.selected) <- c("ensembl", "rep1", "rep2", "rep3")

tpm.selected <- tpm.selected %>% dplyr::rowwise() %>%
  dplyr::mutate(
  group = ifelse(ensembl %in% group1, "group1",
                 ifelse(ensembl %in% group2, "group2",
                        ifelse(ensembl %in% group5, "group5",
                               ifelse(ensembl %in% group8, "group8", NA))))) %>% 
  dplyr::filter(!is.na(group)) %>%
  dplyr::mutate(avgTPM = mean(rep1, rep2, rep3))


ggplot(tpm.selected, aes(x = group, y = avgTPM)) +
  geom_violin(aes(fill = group), show.legend = FALSE) +
  geom_boxplot(width = 0.1, outlier.shape = NA) + 
  scale_y_log10() +
  theme_classic()



  p <- ggplot(temp.tb, aes(x = group, y = score)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + coord_cartesian(ylim = c(ymin, ymax)) +
    annotate("text", x = 1, y = ymin + 1, label = paste0("p12: ", convPvalue(p12), "\n",
                                                         "p15: ", convPvalue(p15), "\n",
                                                         "p18: ", convPvalue(p18), "\n",
                                                         "p25: ", convPvalue(p25), "\n",
                                                         "p28: ", convPvalue(p28), "\n",
                                                         "p58: ",convPvalue( p58), "\n"),
             color = "black", hjust = 0, size = 3)
  
  
  fileName <- paste0("insulation_score_", note)
  height <- 3
  width <- 3
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()

[2.23] Checking Early gene from Bobbie

dTAG

## Importing groups
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group2.tsv"))$gene
group5 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group5.tsv"))$gene
group8 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_group8.tsv"))$gene


## Importing Bobbie gene classification
geneCluster <- fread(here(refDir, "bobbie_gene_classification.csv")) %>%
  dplyr::select(gene, enst, Cluster)
colnames(geneCluster) <- c("gene", "ensembl_transcript_id", "cluster")


## Converting transcript ID to gene ID
idPair_tg <- getBM(attributes = c("ensembl_transcript_id", "ensembl_gene_id"),
                 filters = "ensembl_transcript_id",
                 values = geneCluster$ensembl_transcript,
                 mart = ensembl.v102)
geneCluster <- geneCluster %>% dplyr::left_join(idPair_tg, by = c("ensembl_transcript_id"))

# Making data for stacked barplot
countGene <- function(geneCluster, groupName, clusterName){
  num <- nrow(geneCluster %>% dplyr::filter(ensembl_gene_id %in% groupName,
                                            cluster %in% clusterName))
  return(num)
}
countGeneList <- function(geneCluster, groupName){
  n1 <- countGene(geneCluster, groupName, "Early")
  n2 <- countGene(geneCluster, groupName, "Middle")
  n3 <-countGene(geneCluster, groupName, "Late")
  n4 <- countGene(geneCluster, groupName, "Transient")
  return(c(n1, n2, n3, n4))
}

group <- c(rep("group1", 4), rep("group2", 4), rep("group3", 4), rep("group4", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 4)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, group1),
           countGeneList(geneCluster, group2),
           countGeneList(geneCluster, group5),
           countGeneList(geneCluster, group8))

data <- data.frame(group, cluster, value)


# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()


# Statistical analysis 
# Similar to the Chi-Square test, Fisher’s Exact Test is used when you have smaller sample sizes or when the expected frequency in any cell of the contingency table is below 5.
temp <- data %>% dplyr::filter(group %in% c("group1", "group2"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

temp <- data %>% dplyr::filter(group %in% c("group1", "group3"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

temp <- data %>% dplyr::filter(group %in% c("group1", "group4"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result


### P-N
resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

pnOver8 <- (temp2 %>% dplyr::filter(total >= 8))$gene
pnOver6 <- (temp2 %>% dplyr::filter(total >= 6, total < 8))$gene
pnOver4 <- (temp2 %>% dplyr::filter(total >= 4, total < 6))$gene
pnOver2 <- (temp2 %>% dplyr::filter(total >= 2, total < 4))$gene
pnOver0 <- (temp2 %>% dplyr::filter(total < 2))$gene

group <- c(rep("pnOver8", 4), rep("pnOver6", 4), rep("pnOver4", 4), rep("pnOver2", 4), rep("pnOver0", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 5)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, pnOver8),
           countGeneList(geneCluster, pnOver6),
           countGeneList(geneCluster, pnOver4),
           countGeneList(geneCluster, pnOver2),
           countGeneList(geneCluster, pnOver0))

data <- data.frame(group, cluster, value)
# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()

temp <- data %>% dplyr::filter(group %in% c("pnOver2", "pnOver8"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

### P-S
psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene

group <- c(rep("psOver4", 4), rep("psOver3", 4), rep("psOver2", 4), rep("psOver1", 4), rep("psOver0", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 5)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, psOver4),
           countGeneList(geneCluster, psOver3),
           countGeneList(geneCluster, psOver2),
           countGeneList(geneCluster, psOver1),
           countGeneList(geneCluster, psOver0))

data <- data.frame(group, cluster, value)
# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()
temp <- data %>% dplyr::filter(group %in% c("psOver2", "psOver4"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

### P-E
peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene

group <- c(rep("peOver4", 4), rep("peOver3", 4), rep("peOver2", 4), rep("peOver1", 4), rep("peOver0", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 5)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, peOver4),
           countGeneList(geneCluster, peOver3),
           countGeneList(geneCluster, peOver2),
           countGeneList(geneCluster, peOver1),
           countGeneList(geneCluster, peOver0))

data <- data.frame(group, cluster, value)
# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()

### P-P
ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene

group <- c(rep("ppOver4", 4), rep("ppOver3", 4), rep("ppOver2", 4), rep("ppOver1", 4), rep("ppOver0", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 5)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, ppOver4),
           countGeneList(geneCluster, ppOver3),
           countGeneList(geneCluster, ppOver2),
           countGeneList(geneCluster, ppOver1),
           countGeneList(geneCluster, ppOver0))
data <- data.frame(group, cluster, value)
# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()

A485

## Importing groups
group1 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group2.tsv"))$gene
group3 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group3.tsv"))$gene
group4 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group4.tsv"))$gene
group5 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group5.tsv"))$gene
group6 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group6.tsv"))$gene
group7 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group7.tsv"))$gene
group8 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group8.tsv"))$gene
group9 <- fread(here(refDir, "geneList_A485_vs_DMSO_RNA_loop_group9.tsv"))$gene


## Importing Bobbie gene classification
geneCluster <- fread(here(refDir, "bobbie_gene_classification.csv")) %>%
  dplyr::select(gene, enst, Cluster)
colnames(geneCluster) <- c("gene", "ensembl_transcript_id", "cluster")


## Converting transcript ID to gene ID
idPair_tg <- getBM(attributes = c("ensembl_transcript_id", "ensembl_gene_id"),
                 filters = "ensembl_transcript_id",
                 values = geneCluster$ensembl_transcript,
                 mart = ensembl.v102)
geneCluster <- geneCluster %>% dplyr::left_join(idPair_tg, by = c("ensembl_transcript_id"))

# Making data for stacked barplot
countGene <- function(geneCluster, groupName, clusterName){
  num <- nrow(geneCluster %>% dplyr::filter(ensembl_gene_id %in% groupName,
                                            cluster %in% clusterName))
  return(num)
}
countGeneList <- function(geneCluster, groupName){
  n1 <- countGene(geneCluster, groupName, "Early")
  n2 <- countGene(geneCluster, groupName, "Middle")
  n3 <-countGene(geneCluster, groupName, "Late")
  n4 <- countGene(geneCluster, groupName, "Transient")
  return(c(n1, n2, n3, n4))
}

group <- c(rep("group1", 4), rep("group2", 4), rep("group3", 4),
           rep("group4", 4), rep("group5", 4), rep("group6", 4),
           rep("group7", 4), rep("group8", 4), rep("group9", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 9)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(countGeneList(geneCluster, group1),
           countGeneList(geneCluster, group2),
           countGeneList(geneCluster, group3),
           countGeneList(geneCluster, group4),
           countGeneList(geneCluster, group5),
           countGeneList(geneCluster, group6),
           countGeneList(geneCluster, group7),
           countGeneList(geneCluster, group8),
           countGeneList(geneCluster, group9))

data <- data.frame(group, cluster, value)


# Plotting
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()


# Statistical analysis 
# Similar to the Chi-Square test, Fisher’s Exact Test is used when you have smaller sample sizes or when the expected frequency in any cell of the contingency table is below 5.
temp <- data %>% dplyr::filter(group %in% c("group1", "group2"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

temp <- data %>% dplyr::filter(group %in% c("group1", "group3"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

temp <- data %>% dplyr::filter(group %in% c("group1", "group4"))
contingency_table <- xtabs(value ~ group + cluster, data = temp)
fisher_result <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 100000)
fisher_result

[2.24] Checking bookmarking

  1. Checking whether subset of regulatory loop have bookmarking
  2. Checking whether loops related to genes have bookmarking H3K27ac_effie ATAC_effie TBP Oct4_effie, Oct4_dsg Sox2_effie, Sox2_dsg Esrrb_dsg Klf4_effie CTCF ##### Functions
extractAnchor <- function(loop){
  anchor1 <- loop %>% dplyr::select(c(1, 2, 3))
  colnames(anchor1) <- c("chr", "start", "end")
  anchor2 <- loop %>% dplyr::select(c(4, 5, 6))
  colnames(anchor2) <- c("chr", "start", "end")
  anchors <- reduce(makeGRangesFromDataFrame(bind_rows(anchor1, anchor2)))
    return(anchors)
}

runFisherExact <- function(interest.gr, background.gr, query.gr){
  overlaps_interest <- countOverlaps(interest.gr, query.gr)
  a <- sum(overlaps_interest > 0)
  total_interest <- length(interest.gr)
  c <- total_interest - a
  
  overlaps_background <- countOverlaps(background.gr, query.gr)
  b <- sum(overlaps_background > 0)
  total_background <- length(background.gr)
  d <- total_background - b
  
  # Construct contingency table
  contingency_table <- matrix(c(a, c, b, d), nrow=2, byrow=TRUE,
                              dimnames=list("Region" = c("interest.gr", "background.gr"),
                                            "Overlap" = c("Yes", "No")))
  
  # Perform Fisher's exact test
  fisher_result <- fisher.test(contingency_table)
  
  return(fisher_result)
}

runFisherExactCombination <- function(interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr, lost.gr){
  # SEEDING
  temp <- runFisherExact(loop.up.gr, background.gr, retained.gr)
  result.tb <- tibble(interest = paste0(interestName, "_UP"),
                      target = paste0(targetName, "_retained"),
                      pvalue = temp$p.value,
                      oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.no.gr, background.gr, retained.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_NO"),
            target = paste0(targetName, "_retained"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.down.gr, background.gr, retained.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_DOWN"),
            target = paste0(targetName, "_retained"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.up.gr, background.gr, lost.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_UP"),
            target = paste0(targetName, "_lost"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.no.gr, background.gr, lost.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_NO"),
            target = paste0(targetName, "_lost"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.down.gr, background.gr, lost.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_DOWN"),
            target = paste0(targetName, "_lost"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  return(result.tb)
}

runFisherExactCombinationBinary <- function(interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr, lost.gr){
  # SEEDING
  temp <- runFisherExact(loop.upno.gr, background.gr, retained.gr)
  result.tb <- tibble(interest = paste0(interestName, "_UP/NO"),
                      target = paste0(targetName, "_retained"),
                      pvalue = temp$p.value,
                      oddsRatio = temp$estimate)
  

  # ADDING ROWS
  temp <- runFisherExact(loop.down.gr, background.gr, retained.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_DOWN"),
            target = paste0(targetName, "_retained"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.upno.gr, background.gr, lost.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_UP/NO"),
            target = paste0(targetName, "_lost"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)

  
  # ADDING ROWS
  temp <- runFisherExact(loop.down.gr, background.gr, lost.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_DOWN"),
            target = paste0(targetName, "_lost"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  return(result.tb)
}

runFisherExactCombinationRetained <- function(interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr){
  # SEEDING
  temp <- runFisherExact(loop.up.gr, background.gr, retained.gr)
  result.tb <- tibble(interest = paste0(interestName, "_UP"),
                      target = paste0(targetName, "_retained"),
                      pvalue = temp$p.value,
                      oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.no.gr, background.gr, retained.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_NO"),
            target = paste0(targetName, "_retained"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  # ADDING ROWS
  temp <- runFisherExact(loop.down.gr, background.gr, retained.gr)
  result.tb <- result.tb %>% 
    add_row(interest = paste0(interestName, "_DOWN"),
            target = paste0(targetName, "_retained"),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  

  return(result.tb)
}

runFisherExactCombinationTarget <- function(targetName, interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr){
  # RETAINED loop
  retained <- fread(here(refDir, "TF_bookmarking", targetName, "am_a.bed")) %>% dplyr::select(c(1, 2, 3))
  colnames(retained) <- c("chr", "start", "end")
  retained.gr <- makeGRangesFromDataFrame(retained)
  # LOST loop
  lost <- fread(here(refDir, "TF_bookmarking", targetName, "oa.bed")) %>% dplyr::select(c(1, 2, 3))
  colnames(lost) <- c("chr", "start", "end")
  lost.gr <- makeGRangesFromDataFrame(lost)
  
  result <- runFisherExactCombination(interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr, lost.gr)
  
  return(result)
}

runFisherExactCombinationTargetBinary <- function(targetName, interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr){
  # RETAINED loop
  retained <- fread(here(refDir, "TF_bookmarking", targetName, "am_a.bed")) %>% dplyr::select(c(1, 2, 3))
  colnames(retained) <- c("chr", "start", "end")
  retained.gr <- makeGRangesFromDataFrame(retained)
  # LOST loop
  lost <- fread(here(refDir, "TF_bookmarking", targetName, "oa.bed")) %>% dplyr::select(c(1, 2, 3))
  colnames(lost) <- c("chr", "start", "end")
  lost.gr <- makeGRangesFromDataFrame(lost)
  
  result <- runFisherExactCombinationBinary(interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr, lost.gr)
  
  return(result)
}

runFisherExactCombinationTargetRetained <- function(targetName, interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr){
  # RETAINED loop
  retained <- fread(here(refDir, "TF_bookmarking", targetName, "am_a.bed")) %>% dplyr::select(c(1, 2, 3))
  colnames(retained) <- c("chr", "start", "end")
  retained.gr <- makeGRangesFromDataFrame(retained)
  # LOST loop
  result <- runFisherExactCombinationRetained(interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr,
                                      targetName,
                                      retained.gr)
  
  return(result)
}
All loops
#### Importing loops of interest
interestName <- "allLoop"
# BACKGROUND loop
background <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all.bedpe"))
background.gr <- (extractAnchor(background))
# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.up.gr <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe"))
loop.no.gr <- (extractAnchor(loop.no))
# DOWN loop
loopNum <- nrow(loop.no)
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
loop.down <- loop.all %>% dplyr::filter(diff_dTAG_DMSO < -0.2) %>% dplyr::arrange(diff_dTAG_DMSO) %>% slice_head(n = loopNum)
loop.down.gr <- (extractAnchor(loop.down))

#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("ESRRB_NCB", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("ESRRB_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("NANOG_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp11 <- runFisherExactCombinationTarget("OCT4_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp12 <- runFisherExactCombinationTarget("OCT4_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp13 <- runFisherExactCombinationTarget("SMC1", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp14 <- runFisherExactCombinationTarget("SOX2_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp15 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp16 <- runFisherExactCombinationTarget("SOX2_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp17 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10,
         temp11, temp12, temp13, temp14, temp15, temp16 ,temp17)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 5), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3, 4, 5), 
                                    labels = c("0", "1", "2", "3", "4", "5")))
All loops refined


#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("OCT4_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("SMC1", interestName,
                                     loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))
Reg loops
#### Importing loops of interest
interestName <- "regLoop"
# BACKGROUND loop
background <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))
background.gr <- (extractAnchor(background))
# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.up.gr <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
loop.no.gr <- (extractAnchor(loop.no))
# UPNO loop
loop.upno <- bind_rows(loop.up, loop.no)
loop.upno.gr <- extractAnchor(loop.upno)
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
loop.down.gr <- (extractAnchor(loop.down))
Figure - H3K27ac only
targetName <- "H3K27ac_effie"
# RETAINED loop
retained <- fread(here(refDir, "TF_bookmarking", targetName, "am_a.bed")) %>% dplyr::select(c(1, 2, 3))
colnames(retained) <- c("chr", "start", "end")
retained.gr <- makeGRangesFromDataFrame(retained)
# LOST loop
lost <- fread(here(refDir, "TF_bookmarking", targetName, "oa.bed")) %>% dplyr::select(c(1, 2, 3))
colnames(lost) <- c("chr", "start", "end")
lost.gr <- makeGRangesFromDataFrame(lost)


# SEEDING
temp <- runFisherExact(loop.upno.gr, background.gr, retained.gr)
result.tb <- tibble(interest = paste0(interestName, "_UP/NO"),
                    target = paste0(targetName, "_retained"),
                    pvalue = temp$p.value,
                    oddsRatio = temp$estimate)

# ADDING ROWS
temp <- runFisherExact(loop.down.gr, background.gr, retained.gr)
result.tb <- result.tb %>% 
  add_row(interest = paste0(interestName, "_DOWN"),
          target = paste0(targetName, "_retained"),
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

# ADDING ROWS
temp <- runFisherExact(loop.upno.gr, background.gr, lost.gr)
result.tb <- result.tb %>% 
  add_row(interest = paste0(interestName, "_UP/NO"),
          target = paste0(targetName, "_lost"),
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

# ADDING ROWS
temp <- runFisherExact(loop.down.gr, background.gr, lost.gr)
result.tb <- result.tb %>% 
  add_row(interest = paste0(interestName, "_DOWN"),
          target = paste0(targetName, "_lost"),
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)


result.tb <- result.tb %>%
  mutate(interest = recode(interest, 
                           "regLoop_UP/NO" = "UP/NO",
                           "regLoop_DOWN" = "DOWN"),
         target = recode(target,
                         "H3K27ac_effie_retained" = "Retained",
                         "H3K27ac_effie_lost" = "Lost"))

result.tb$interest <- factor(result.tb$interest, levels = c("UP/NO", "DOWN"))

p <- ggplot(result.tb, aes(x = interest, y = target, size = -log10(pvalue), fill = oddsRatio)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 0.5*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(1, 3)) +  # Set min and max point sizes here
  scale_fill_gradientn(colors = c("#4852A0", "white", "#CB333A"),  # Define gradient colors
                      values = scales::rescale(c(0.5, 1, 1.5)), limits = c(0.5, 1.5), 
                      #low = "white", high = "#CB333A",
                      #                  limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) +
  labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "heatmap_H3K27ac_bookmarking_reg_dotplot")
width <- panelSize(1.7)*mmToInch
height <- panelSize(1.1)*mmToInch
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
svglite(paste0(fileName, ".svg"),  height = height, width = width)
print(p)
dev.off()

  
Figure - all targets
#### Importing loops of target

temp1 <- runFisherExactCombinationTargetBinary("ESRRB_dsg", interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTargetBinary("H3K27ac_effie", interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTargetBinary("KLF4_effie", interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTargetBinary("OCT4_effie", interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTargetBinary("SOX2_effie", interestName,
                                      loop.upno.gr, loop.down.gr,
                                      background.gr)


data <- bind_rows(temp1, temp2, temp3, temp4, temp5)



result.tb <- data %>%
  mutate(interest = recode(interest, 
                           "regLoop_UP/NO" = "UP/NO",
                           "regLoop_DOWN" = "DOWN"),
         target = recode(target,
                         "H3K27ac_effie_retained" = "H3K27ac_retained",
                         "H3K27ac_effie_lost" = "H3K27ac_lost",
                         "ESRRB_dsg_retained" = "ESRRB_retained",
                         "ESRRB_dsg_lost" = "ESRRB_lost",
                         "KLF4_effie_retained" = "KLF4_retained",
                         "KLF4_effie_lost" = "KLF4_lost",
                         "OCT4_effie_retained" = "OCT4_retained",
                         "OCT4_effie_lost" = "OCT4_lost",
                         "SOX2_effie_retained" = "SOX2_retained",
                         "SOX2_effie_lost" = "SOX2_lost"))

result.tb$interest <- factor(result.tb$interest, levels = c("UP/NO", "DOWN"))
result.tb$target <- factor(result.tb$target, levels = rev(c("H3K27ac_retained", "H3K27ac_lost",
                                                        "ESRRB_retained", "ESRRB_lost",
                                                        "KLF4_retained", "KLF4_lost",
                                                        "OCT4_retained", "OCT4_lost",
                                                        "SOX2_retained","SOX2_lost")))

p <- ggplot(result.tb, aes(x = interest, y = target, size = -log10(pvalue), fill = oddsRatio)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(1, 3)) +  # Set min and max point sizes here
  scale_fill_gradientn(colors = c("#4852A0", "white", "#CB333A"),  # Define gradient colors
                      values = scales::rescale(c(0.5, 1, 1.5)), limits = c(0.5, 1.5), 
                      #low = "white", high = "#CB333A",
                      #                  limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) +
  labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "heatmap_alltarget_bookmarking_reg_dotplot")
width <- panelSize(2.2)*mmToInch
height <- panelSize(2)*mmToInch
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
svglite(paste0(fileName, ".svg"),  height = height, width = width)
print(p)
dev.off()
Retained & Lost
#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("ESRRB_NCB", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("ESRRB_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("NANOG_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp11 <- runFisherExactCombinationTarget("OCT4_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp12 <- runFisherExactCombinationTarget("OCT4_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp13 <- runFisherExactCombinationTarget("SMC1", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp14 <- runFisherExactCombinationTarget("SOX2_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp15 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp16 <- runFisherExactCombinationTarget("SOX2_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp17 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10,
         temp11, temp12, temp13, temp14, temp15, temp16 ,temp17)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 5), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3, 4, 5), 
                                    labels = c("0", "1", "2", "3", "4", "5")))
Retained

#### Importing loops of target
temp1 <- runFisherExactCombinationTargetRetained("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTargetRetained("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTargetRetained("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTargetRetained("ESRRB_NCB", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTargetRetained("ESRRB_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTargetRetained("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTargetRetained("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTargetRetained("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTargetRetained("NANOG_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTargetRetained("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp11 <- runFisherExactCombinationTargetRetained("OCT4_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp12 <- runFisherExactCombinationTargetRetained("OCT4_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp13 <- runFisherExactCombinationTargetRetained("SMC1", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp14 <- runFisherExactCombinationTargetRetained("SOX2_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp15 <- runFisherExactCombinationTargetRetained("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp16 <- runFisherExactCombinationTargetRetained("SOX2_pfa", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp17 <- runFisherExactCombinationTargetRetained("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10,
         temp11, temp12, temp13, temp14, temp15, temp16 ,temp17)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))

Reg refined

Retained & Lost


#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("SMC1", interestName,
                                     loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))
Retained


#### Importing loops of target
temp1 <- runFisherExactCombinationTargetRetained("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTargetRetained("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTargetRetained("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTargetRetained("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTargetRetained("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTargetRetained("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTargetRetained("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTargetRetained("SMC1", interestName,
                                     loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTargetRetained("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTargetRetained("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))

[2.24.2] Checking bookmarking - A485

All loops

#### Importing loops of interest
interestName <- "allLoop"
# BACKGROUND loop
background <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all.bedpe"))
background.gr <- (extractAnchor(background))
# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_UP_diff0.2.bedpe"))
loop.up.gr <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_NO_diff0.2.bedpe"))
loop.no.gr <- (extractAnchor(loop.no))
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_DOWN_diff0.2.bedpe"))
loop.down.gr <- (extractAnchor(loop.down))
All loops refined


#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("OCT4_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("SMC1", interestName,
                                     loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))

Reg loops

#### Importing loops of interest
interestName <- "regLoop"
# BACKGROUND loop
background <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))
background.gr <- (extractAnchor(background))
# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe"))
loop.up.gr <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe"))
loop.no.gr <- (extractAnchor(loop.no))
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe"))
loop.down.gr <- (extractAnchor(loop.down))

fwrite(as_tibble(loop.up.gr) %>% dplyr::select(seqnames, start, end), here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.anchor.bed"), col.names = FALSE, sep = "\t")
fwrite(as_tibble(loop.no.gr) %>% dplyr::select(seqnames, start, end), here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.anchor.bed"), col.names = FALSE, sep = "\t")
fwrite(as_tibble(loop.down.gr) %>% dplyr::select(seqnames, start, end), here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.anchor.bed"), col.names = FALSE, sep = "\t")
Retained & Lost


#### Importing loops of target
temp1 <- runFisherExactCombinationTarget("ATAC_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp2 <- runFisherExactCombinationTarget("CTCF", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp3 <- runFisherExactCombinationTarget("ESRRB_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp4 <- runFisherExactCombinationTarget("H3K27ac_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp5 <- runFisherExactCombinationTarget("KLF4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp6 <- runFisherExactCombinationTarget("NANOG_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp7 <- runFisherExactCombinationTarget("OCT4_effie", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp8 <- runFisherExactCombinationTarget("SMC1", interestName,
                                     loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp9 <- runFisherExactCombinationTarget("SOX2_dsg", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)
temp10 <- runFisherExactCombinationTarget("TBP", interestName,
                                      loop.up.gr, loop.no.gr, loop.down.gr,
                                      background.gr)




data <- bind_rows(temp1, temp2, temp3, temp4, temp5,
         temp6, temp7, temp8, temp9, temp10)

# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 3), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3), 
                                    labels = c("0", "1", "2", "3")))

DEGs from RNA-seq

2.5kb from TSS, at least 1 bp overlap #### 2i

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V1, TSS, V6)
colnames(gene.tb) <- c("chr", "TSS", "ensembl")

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
diff.RNA <- diff.RNA %>% dplyr::left_join(gene.tb, by = c("ensembl_gene_id" = "ensembl")) %>%
  dplyr::filter(!is.na(TSS))
alpha <- 0.05
fcCutoff <- 0.5

diff.RNA <- diff.RNA %>% dplyr::mutate(diff = case_when(padj < alpha & shrinked_log2FC > fcCutoff ~ "UP",
                                                        padj < alpha & shrinked_log2FC < -fcCutoff ~ "DOWN",
                                                        TRUE ~ "NO"))


temp <- diff.RNA %>% dplyr::mutate(start = TSS - 2500,
                           end = TSS + 2500) %>%
  dplyr::select(chr, start, end, ensembl_gene_id, diff)


down.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "DOWN"))
up.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "UP"))
no.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "NO"))
all.gr <- makeGRangesFromDataFrame(temp)

data <- runFisherExactCombinationTarget("H3K27ac_effie", "TSS",
                                      up.gr, no.gr, down.gr,
                                      all.gr)


# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 2), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2), 
                                    labels = c("0", "1", "2")))


## GO TEST
diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
diff.RNA <- diff.RNA %>% dplyr::left_join(gene.tb, by = c("ensembl_gene_id" = "ensembl")) %>%
  dplyr::filter(!is.na(TSS))
alpha <- 0.05
fcCutoff <- 0.5

diff.RNA <- diff.RNA %>% dplyr::mutate(diff = case_when(padj < alpha & shrinked_log2FC > fcCutoff ~ "UP",
                                                        padj < alpha & shrinked_log2FC < -fcCutoff ~ "DOWN",
                                                        TRUE ~ "NO"))
geneList <- (diff.RNA %>% dplyr::filter(diff == "DOWN"))$ensembl_gene_id
GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)

downStemGene <- unique(unlist((as.data.frame(GO) %>% dplyr::slice(c(4, 5, 14, 66)) %>% dplyr::mutate(geneID = strsplit(geneID, "/")))$geneID))
downStem.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(ensembl_gene_id %in% downStemGene))

print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))
geneList <- (diff.RNA %>% dplyr::filter(diff == "UP"))$ensembl_gene_id
GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)
print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))


downNONStem.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "DOWN",
                                                               !(ensembl_gene_id %in% downStemGene)))

print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))
geneList <- (diff.RNA %>% dplyr::filter(diff == "UP"))$ensembl_gene_id
GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)
print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))



### Checking bookmarking only in stem gene

data <- runFisherExactCombinationTarget("H3K27ac_effie", "TSS",
                                      down.gr, downNONStem.gr, downStem.gr,
                                      all.gr)


# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 2), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2), 
                                    labels = c("0", "1", "2")))

Epi

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V1, TSS, V6)
colnames(gene.tb) <- c("chr", "TSS", "ensembl")

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.Epi.A485_vs_G1.Epi.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
diff.RNA <- diff.RNA %>% dplyr::left_join(gene.tb, by = c("ensembl_gene_id" = "ensembl")) %>%
  dplyr::filter(!is.na(TSS))
alpha <- 0.05
fcCutoff <- 0.5

diff.RNA <- diff.RNA %>% dplyr::mutate(diff = case_when(padj < alpha & shrinked_log2FC > fcCutoff ~ "UP",
                                                        padj < alpha & shrinked_log2FC < -fcCutoff ~ "DOWN",
                                                        TRUE ~ "NO"))


temp <- diff.RNA %>% dplyr::mutate(start = TSS - 2500,
                           end = TSS + 2500) %>%
  dplyr::select(chr, start, end, ensembl_gene_id, diff)


down.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "DOWN"))
up.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "UP"))
no.gr <- makeGRangesFromDataFrame(temp %>% dplyr::filter(diff == "NO"))
all.gr <- makeGRangesFromDataFrame(temp)

data <- runFisherExactCombinationTarget("H3K27ac_effie", "TSS",
                                      up.gr, no.gr, down.gr,
                                      all.gr)


# Visualization
library(circlize)

heatmap_data <- data %>% dplyr::select(target, interest, oddsRatio) %>%
pivot_wider(names_from = interest, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, interest, pvalue) %>%
  pivot_wider(names_from = interest, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 2), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2), 
                                    labels = c("0", "1", "2")))


## GO
diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.Epi.A485_vs_G1.Epi.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
diff.RNA <- diff.RNA %>% dplyr::left_join(gene.tb, by = c("ensembl_gene_id" = "ensembl")) %>%
  dplyr::filter(!is.na(TSS))
alpha <- 0.05
fcCutoff <- 0.5

diff.RNA <- diff.RNA %>% dplyr::mutate(diff = case_when(padj < alpha & shrinked_log2FC > fcCutoff ~ "UP",
                                                        padj < alpha & shrinked_log2FC < -fcCutoff ~ "DOWN",
                                                        TRUE ~ "NO"))

geneList <- (diff.RNA %>% dplyr::filter(diff == "DOWN"))$ensembl_gene_id
GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)
print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))
geneList <- (diff.RNA %>% dplyr::filter(diff == "UP"))$ensembl_gene_id
GO <- enrichGO(gene = geneList, OrgDb = org.Mm.eg.db, keyType = "ENSEMBL", ont = "BP")
GO.readable <- setReadable(GO, OrgDb = org.Mm.eg.db)
print(dotplot(GO, showCategory = 15, title = "") + 
        scale_color_continuous(limits = c(0, 0.05), low = "red", high = "black"))

[2.26] Checking the ChIP intensity at anchors

This doesn’t have to be restricted to P-N loops. Let’s check all loops first. Also instead of density (mean), median could be better choice. Sum is not appropriate here since the size of anchors are not same. #### Limited to peaks to reduce noise ##### dTAG

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(loop ==group1) )$sumScore
  distance2 <- (data %>% dplyr::filter(loop ==group2) )$sumScore
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

name <- "chromo_cons_annoHierarchy"

# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
# UP NO
loop.upno <- bind_rows(loop.up, loop.no)
anchor.upno <- (extractAnchor(loop.upno))
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))

getSumScores <- function(track, anchor) {
  # Find overlaps between all anchors and track regions at once
  overlaps <- findOverlaps(anchor, track)
  
  # Extract the scores and corresponding anchor indices
  anchor_indices <- queryHits(overlaps)
  track_scores <- score(track)[subjectHits(overlaps)]
  
  # Use tapply to calculate the median scores for each anchor
  median_scores <- tapply(track_scores, anchor_indices, mean, na.rm = TRUE)
  
  # Initialize a numeric vector to store the median scores for each anchor
  all_median_scores <- rep(NA, length(anchor))
  
  # Populate the median scores for the anchors that have overlaps
  all_median_scores[as.numeric(names(median_scores))] <- median_scores
  
  return(all_median_scores)
}

plotSumScores <- function(track, peak, name){
  peakTrack <- track[unique(queryHits(findOverlaps(track, peak)))]
  a <- getSumScores(peakTrack, anchor.up)
  b <- getSumScores(peakTrack, anchor.no)
  c <- getSumScores(peakTrack, anchor.down)
  a.tb <- tibble(loop = "UP",
                 sumScore = a)
  b.tb <- tibble(loop = "NO",
                 sumScore = b)
  c.tb <- tibble(loop = "DOWN",
                 sumScore = c)
  data <- bind_rows(a.tb, b.tb, c.tb) %>% drop_na()
  ggplot(data, aes(x = loop, y = sumScore)) + 
    labs(x = NULL, y = paste0(name, " average peak score per anchor")) +
    geom_violin(aes(fill = group), color = "black",
                linewidth = lineThick * mmToLineUnit, lineend = "square",
                show.legend = FALSE) +
    geom_boxplot(width = 0.1, color = "black",
                 linewidth = lineThick * mmToLineUnit, lineend = "square",
                 outlier.size = 1, outlier.stroke = NA) + theme_classic() +
    stat_summary(
      aes(group = loop), fun = mean,
      geom = "point", shape = 21, size = 1,
      fill = "red", color = "black"
    ) +
    coord_cartesian(ylim = c(0, quantile(data$sumScore, 0.95))) + theme(
    axis.title = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )
}

plotSumScoresBinary <- function(track, peak, name, anchor.upno, anchor.down){
  peakTrack <- track[unique(queryHits(findOverlaps(track, peak)))]
  b <- getSumScores(peakTrack, anchor.upno)
  c <- getSumScores(peakTrack, anchor.down)
  b.tb <- tibble(loop = "UP/NO",
                 sumScore = b)
  c.tb <- tibble(loop = "DOWN",
                 sumScore = c)
  data <- bind_rows(b.tb, c.tb) %>% drop_na()
  data$loop <- factor(data$loop, levels = c("UP/NO", "DOWN"))
  
  p12 <- getPvalWilcox(data, "UP/NO", "DOWN")
  p <-  ggplot(data, aes(x = name, fill = loop, y = sumScore)) + 
    labs(x = NULL, y = paste0("Average ChIP peak score at anchor)")) +
    introdataviz::geom_split_violin(linewidth = lineThick * mmToLineUnit, lineend = "square",
                                    alpha = .4) +
    geom_boxplot(width = 0.3, color = "black",
                 linewidth = lineThick * mmToLineUnit, lineend = "square",
                 outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + theme_classic() +
    stat_summary(
      aes(group = loop), fun = mean,
      geom = "point", shape = 21, size = 0.5,
      fill = "black", color = "black", position = position_dodge(.3)
    ) + theme(
      axis.title = element_text(
        size = fontSizeM, family = fontType, color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeM, family = fontType, color = "#000000"
      ),
      axis.text.x = element_text(
        angle = 0,
      ),
      axis.text.y = element_text(
        size = fontSizeS,
      ),
      axis.line = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
      legend.text = element_text(family = fontType, size = fontSizeS),
      legend.title = element_text(family = fontType, size = fontSizeS)
    ) + 
    coord_cartesian(ylim = c(quantile(data$sumScore, 0.0), quantile(data$sumScore, 0.9))) + 
    annotate(
     "text", x = 1, y = quantile(data$sumScore, 0.5),
     label = paste0("p12: ", convPvalue(p12)),
     color = "black", hjust = 0, size = 3
   ) +   guides(
    fill = guide_legend(
        keywidth = 0.2,  # Adjust the width of the legend keys
        keyheight = 0.2  # Adjust the height of the legend keys
    )
  )
  
   fileName <- paste0("ChIP_peak_avgPeakScore_", name)
  width <- panelSize(1.5)*mmToInch
  height <- panelSize(1.2)*mmToInch
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# Sum peak score
####
track <- import(here(refDir, "33255_H3K4me3_04-745_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
#plotSumScores(track, peak, "H3K4me3")
plotSumScoresBinary(track, peak, "H3K4me3", anchor.upno, anchor.down)

track <- import(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
#plotSumScores(track, peak, "H3K27ac")
plotSumScoresBinary(track, peak, "H3K27ac", anchor.upno, anchor.down)

track <- import(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.black.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.bed"))
#plotSumScores(track, peak, "H3K14ac")
plotSumScoresBinary(track, peak, "H3K14ac", anchor.upno, anchor.down)

track <- import(here(refDir, "33248_CTCF_07-729_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
#plotSumScores(track, peak, "CTCF")
plotSumScoresBinary(track, peak, "CTCF", anchor.upno, anchor.down)

track <- import(here(refDir, "33250_RAD21_ab992_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))
#plotSumScores(track, peak, "RAD21")
plotSumScoresBinary(track, peak, "RAD21", anchor.upno, anchor.down)
A485
name <- "chromo_cons_annoHierarchy"

# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))

getSumScores <- function(track, anchor) {
  # Find overlaps between all anchors and track regions at once
  overlaps <- findOverlaps(anchor, track)
  
  # Extract the scores and corresponding anchor indices
  anchor_indices <- queryHits(overlaps)
  track_scores <- score(track)[subjectHits(overlaps)]
  
  # Use tapply to calculate the median scores for each anchor
  median_scores <- tapply(track_scores, anchor_indices, sum, na.rm = TRUE)
  
  # Initialize a numeric vector to store the median scores for each anchor
  all_median_scores <- rep(NA, length(anchor))
  
  # Populate the median scores for the anchors that have overlaps
  all_median_scores[as.numeric(names(median_scores))] <- median_scores
  
  return(all_median_scores)
}

plotSumScores <- function(track, peak, name){
  peakTrack <- track[unique(queryHits(findOverlaps(track, peak)))]
  a <- getSumScores(peakTrack, anchor.up)
  b <- getSumScores(peakTrack, anchor.no)
  c <- getSumScores(peakTrack, anchor.down)
  a.tb <- tibble(loop = "UP",
                 sumScore = a)
  b.tb <- tibble(loop = "NO",
                 sumScore = b)
  c.tb <- tibble(loop = "DOWN",
                 sumScore = c)
  data <- bind_rows(a.tb, b.tb, c.tb) %>% drop_na()
  ggplot(data, aes(x = loop, y = sumScore)) + geom_boxplot(outlier.shape = NA) + theme_classic() + ggtitle(paste0(name, " sum peak")) +
    coord_cartesian(ylim = c(0, quantile(data$sumScore, 0.9)))
}

# Sum peak score
####
track <- import(here(refDir, "33255_H3K4me3_04-745_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
plotSumScores(track, peak, "H3K4me3")

track <- import(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
plotSumScores(track, peak, "H3K27ac")

track <- import(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.black.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.bed"))
plotSumScores(track, peak, "H3K14ac")

track <- import(here(refDir, "33248_CTCF_07-729_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
plotSumScores(track, peak, "CTCF")

track <- import(here(refDir, "33250_RAD21_ab992_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak.temp <- fread(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed")) %>%
  dplyr::mutate(V2 = V2 - 1000,
                V3 = V3 + 1000)
colnames(peak.temp) <- c("chr", "start", "end")
peak <- makeGRangesFromDataFrame(peak.temp)
plotSumScores(track, peak, "YY1")


### For those with only summit
track <- import(here(refDir, "GSM5571895_ESC_YY1_1.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM5571895_ESC_YY1_summit.bed"))
plotSumScores(track, peak, "RAD21")

### FOR THOSE WITHOUT PEAKS
track <- import(here(refDir, "GSM2082708_ESC.H3K27me3.1_mm10Lifted.black.bw"), format = "BigWig")
a <- getSumScores(track, anchor.up)
b <- getSumScores(track, anchor.no)
c <- getSumScores(track, anchor.down)
a.tb <- tibble(loop = "UP",
               sumScore = a)
b.tb <- tibble(loop = "NO",
               sumScore = b)
c.tb <- tibble(loop = "DOWN",
               sumScore = c)
data <- bind_rows(a.tb, b.tb, c.tb) %>% drop_na()
ggplot(data, aes(x = loop, y = sumScore)) + geom_boxplot(outlier.shape = NA) + theme_classic() + ggtitle(paste0("H3K27me3 sum no peak")) +
  coord_cartesian(ylim = c(0, quantile(data$sumScore, 0.9)))

Peak density instead of intensity

name <- "chromo_cons_annoHierarchy"

# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))


peak.H3K4me3 <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
peak.CTCF <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
peak.temp <- fread(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed")) %>%
  dplyr::mutate(V2 = V2 - 1000,
                V3 = V3 + 1000)
colnames(peak.temp) <- c("chr", "start", "end")
peak.RAD21 <- makeGRangesFromDataFrame(peak.temp)


calculatePeakDensity <- function(peak, note){
  
  overlap_counts <- countOverlaps(anchor.up, peak)
  anchor_widths <- (width(anchor.up)-1)/1000
  density <- overlap_counts / anchor_widths
  data1 <- tibble(type = "UP",
                  densityPerKb = density)
  
  overlap_counts <- countOverlaps(anchor.no, peak)
  anchor_widths <- (width(anchor.no)-1)/1000
  density <- overlap_counts / anchor_widths
  mcols(anchor.no)$density <- density
  data2 <- tibble(type = "NO",
                  densityPerKb = density)
  
  overlap_counts <- countOverlaps(anchor.down, peak)
  anchor_widths <- (width(anchor.down)-1)/1000
  density <- overlap_counts / anchor_widths
  mcols(anchor.down)$density <- density
  data3 <- tibble(type = "DOWN",
                  densityPerKb = density)
  
  data <- bind_rows(data1, data2, data3)
  
  ggplot(data, aes(x = type, y = densityPerKb))  + geom_violin() + geom_boxplot(outlier.shape = NA, width = 0.1 ) + theme_bw() + ggtitle(note) +
    coord_cartesian(ylim = c(0, quantile(data$sumScore, 0.9)))
}

calculatePeakDensity(peak.H3K4me3, "H3K4me3")
calculatePeakDensity(peak.H3K27ac, "H3K27ac")
calculatePeakDensity(peak.CTCF, "CTCF")
calculatePeakDensity(peak.RAD21, "RAD21")

[2.27] Overlap with SE?

Q1. How many SEs are covered with Micro-C loops?

name <- "chromo_cons_annoHierarchy"
loop <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))
anchor <- extractAnchor(loop)

### Whyte
n <- length(unique(subjectHits(findOverlaps(anchor, peak.Whyte.SE))))
total <- length(peak.Whyte.SE)
counts <- c(n, total - n)
labels <- paste(c("covered", "NOT covered"), counts)
pie(counts, labels = labels,  main = paste0("Whyte SE coverage \n", total), col = c("grey", "white"))

fileName <- here(figDir, "pie_SE_Whyte")
width <- panelSize(4)*mmToInch
height <- panelSize(4)*mmToInch
# svglite(paste0(fileName, ".svg"), width = width, height =height)
# pie(counts, labels = labels,  main = paste0("Whyte SE coverage \n", total), col = c("grey", "white"),
#     cex = 1, cex.main = 1)
# dev.off()



### Dylan
n <- length(unique(subjectHits(findOverlaps(anchor, peak.Dylan.SE))))
total <- length(peak.Dylan.SE)
counts <- c(n, total - n)
labels <- paste(c("covered", "NOT covered"), counts)
pie(counts, labels = labels, main = paste0("Dylan SE coverage \n", total), col = c("grey", "white"))

fileName <- here(figDir, "pie_SE_Murphy")
width <- panelSize(4)*mmToInch
height <- panelSize(4)*mmToInch
# svglite(paste0(fileName, ".svg"), width = width, height =height)
# pie(counts, labels = labels, main = paste0("Murphy SE coverage \n", total), col = c("grey", "white"))
# 
# dev.off()

Q2. Fisher’s exact test?

dTAG
name <- "chromo_cons_annoHierarchy"
loop <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))

getOverlapLoopNum <- function(loop, peak){
  anchor1 <- GRanges(seqnames = loop$V1, ranges = IRanges(start = loop$V2, end = loop$V3))
  anchor2 <- GRanges(seqnames = loop$V4, ranges = IRanges(start = loop$V5, end = loop$V6))
  a <- queryHits(findOverlaps(anchor1, peak))
  b <- queryHits(findOverlaps(anchor2, peak))
  return(length(unique(c(a, b))))
}

getSEOverlapFisher <- function(allLoop, subsetLoop, peak){
  all.overlap <- getOverlapLoopNum(allLoop, peak)
  all.notOverlap <- nrow(allLoop) - all.overlap
  
  subset.overlap <- getOverlapLoopNum(subsetLoop, peak)
  subset.notOverlap <- nrow(subsetLoop) - subset.overlap
  
  contingency_table <- matrix(c(subset.overlap, subset.notOverlap,
                                all.overlap, all.notOverlap), nrow = 2, byrow = TRUE)
  colnames(contingency_table) <- c("Overlapping", "Not_Overlapping")
  rownames(contingency_table) <- c("All loops", "Subset loops")
  
  # Perform Fisher's Exact Test
  fisher_test_result <- fisher.test(contingency_table)
  return(fisher_test_result)
}



loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
loop.upno <- bind_rows(loop.up, loop.no)
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))

### Dylan
# Seeding
temp <- getSEOverlapFisher(loop, loop.upno, peak.Dylan.SE)
result.tb <- tibble(loopType = "UP/NO",
                    target = "Dylan SE",
                    pvalue = temp$p.value,
                    oddsRatio = temp$estimate)

# temp <- getSEOverlapFisher(loop, loop.up, peak.Dylan.SE)
# result.tb <- tibble(loopType = "UP",
#                     target = "Dylan SE",
#                     pvalue = temp$p.value,
#                     oddsRatio = temp$estimate)
# Add row
# temp <- getSEOverlapFisher(loop, loop.no, peak.Dylan.SE)
# result.tb <- result.tb %>% 
#   add_row(loopType = "NO",
#           target = "Dylan SE",
#           pvalue = temp$p.value,
#           oddsRatio = temp$estimate)

temp <- getSEOverlapFisher(loop, loop.down, peak.Dylan.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "DOWN",
          target = "Dylan SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

### Whyte
# Seeding
# temp <- getSEOverlapFisher(loop, loop.up, peak.Whyte.SE)
# result.tb <- result.tb %>% 
#   add_row(loopType = "UP",
#                     target = "Whyte SE",
#                     pvalue = temp$p.value,
#                     oddsRatio = temp$estimate)

# Add row
temp <- getSEOverlapFisher(loop, loop.upno, peak.Whyte.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "UP/NO",
          target = "Whyte SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

temp <- getSEOverlapFisher(loop, loop.down, peak.Whyte.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "DOWN",
          target = "Whyte SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)


# Visualization
library(circlize)
data <- result.tb
heatmap_data <- data %>% dplyr::select(target, loopType, oddsRatio) %>%
pivot_wider(names_from = loopType, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, loopType, pvalue) %>%
  pivot_wider(names_from = loopType, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 2), 
                      c("#4852A0", "white", "#CB333A"))

p <- Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = fontSizeS, fontfamily = fontType))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        row_names_gp = gpar(fontsize = fontSizeS, fontfamily = fontType),
  column_names_gp = gpar(fontsize = fontSizeS, fontfamily = fontType),
        heatmap_legend_param = list(
          at = c(0, 1, 2),
          labels = c("0", "1", "2"),
          title_gp = gpar(fontfamily = fontType, fontsize = fontSizeS),
          labels_gp = gpar(fontfamily = fontType, fontsize = fontSizeS)
        )
)

# fileName <- here(figDir, "heatmap_SE_enrichment")
# width <- panelSize(1.5)*mmToInch
# height <- panelSize(0.7)*mmToInch
# svglite(paste0(fileName, ".svg"), width = width, height =height)
# print(p)
# dev.off()
# png(paste0(fileName, ".png"), width = width, height =height, res = 600, unit = "in")
# print(p)
# dev.off()

#######################

data$loopType <- factor(data$loopType, levels = c("UP/NO", "DOWN"))
data$target <- factor(data$target, levels = c("Whyte SE", "Dylan SE"))

p <- ggplot(data, aes(x = loopType, y = target, size = -log10(pvalue), fill = oddsRatio)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(1, 3)) +  # Set min and max point sizes here
  scale_fill_gradientn(colors = c("#4852A0", "white", "#CB333A"),  # Define gradient colors
                      values = scales::rescale(c(0.5, 1, 1.5)), limits = c(0.5, 1.5), 
                      #low = "white", high = "#CB333A",
                      #                  limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) +
  labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- here(figDir, "heatmap_SE_enrichment_dotplot")
width <- panelSize(1.8)*mmToInch
height <- panelSize(1.1)*mmToInch
# png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# print(p)
# dev.off()
svglite(paste0(fileName, ".svg"),  height = height, width = width)
print(p)
dev.off()
A485
name <- "chromo_cons_annoHierarchy"
loop <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))

getOverlapLoopNum <- function(loop, peak){
  anchor1 <- GRanges(seqnames = loop$V1, ranges = IRanges(start = loop$V2, end = loop$V3))
  anchor2 <- GRanges(seqnames = loop$V4, ranges = IRanges(start = loop$V5, end = loop$V6))
  a <- queryHits(findOverlaps(anchor1, peak))
  b <- queryHits(findOverlaps(anchor2, peak))
  return(length(unique(c(a, b))))
}

getSEOverlapFisher <- function(allLoop, subsetLoop, peak){
  all.overlap <- getOverlapLoopNum(allLoop, peak)
  all.notOverlap <- nrow(allLoop) - all.overlap
  
  subset.overlap <- getOverlapLoopNum(subsetLoop, peak)
  subset.notOverlap <- nrow(subsetLoop) - subset.overlap
  
  contingency_table <- matrix(c(subset.overlap, subset.notOverlap,
                                all.overlap, all.notOverlap), nrow = 2, byrow = TRUE)
  colnames(contingency_table) <- c("Overlapping", "Not_Overlapping")
  rownames(contingency_table) <- c("All loops", "Subset loops")
  
  # Perform Fisher's Exact Test
  fisher_test_result <- fisher.test(contingency_table)
  return(fisher_test_result)
}



loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe"))

### Dylan
# Seeding
temp <- getSEOverlapFisher(loop, loop.up, peak.Dylan.SE)
result.tb <- tibble(loopType = "UP",
                    target = "Dylan SE",
                    pvalue = temp$p.value,
                    oddsRatio = temp$estimate)
# Add row
temp <- getSEOverlapFisher(loop, loop.no, peak.Dylan.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "NO",
          target = "Dylan SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

temp <- getSEOverlapFisher(loop, loop.down, peak.Dylan.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "DOWN",
          target = "Dylan SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

### Whyte
# Seeding
temp <- getSEOverlapFisher(loop, loop.up, peak.Whyte.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "UP",
                    target = "Whyte SE",
                    pvalue = temp$p.value,
                    oddsRatio = temp$estimate)
# Add row
temp <- getSEOverlapFisher(loop, loop.no, peak.Whyte.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "NO",
          target = "Whyte SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)

temp <- getSEOverlapFisher(loop, loop.down, peak.Whyte.SE)
result.tb <- result.tb %>% 
  add_row(loopType = "DOWN",
          target = "Whyte SE",
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)


# Visualization
library(circlize)
data <- result.tb
heatmap_data <- data %>% dplyr::select(target, loopType, oddsRatio) %>%
pivot_wider(names_from = loopType, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, loopType, pvalue) %>%
  pivot_wider(names_from = loopType, values_from = pvalue) %>%
  column_to_rownames(var = "target")

col_fun <- colorRamp2(c(0, 1, 5), 
                      c("blue", "white", "red"))

Heatmap(as.matrix(heatmap_data),
        name = "Odds Ratio",
        col = col_fun,
        # Add annotation for p-values
        cell_fun = function(j, i, x, y, width, height, fill) {
          pval <- pvalue_data[i, j]
          label <- ifelse(pval > 0.05, "n.s.", sprintf("%.2e", pval))
          grid.text(label, x, y, gp = gpar(fontsize = 10))
        },
        # Customize the heatmap layout
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        cluster_columns = FALSE,
        column_title = "Interest",
        row_title = "Target",
        heatmap_legend_param = list(at = c(0, 1, 2, 3, 4, 5), 
                                    labels = c("0", "1", "2", "3", "4", "5")))

[2.28] Comparing differential loops in dTAG to A485

The question I want to ask here is whether perturbed loops in dTAG experiments are either perturbed or not perturbed in A485 experiment. If there is compensation going on between RAD21 and A485, UP loop in RAD21 should be more DOWN in A485 and vice versa #### Exploratory part

diffCutoff <- 0.2
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")))

 temp <- data
  temp$density <- get_density(temp$diff_dTAG_DMSO, temp$diff_A485_DMSO, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  
  p1 <- ggplot(temp, aes(x = diff_dTAG_DMSO, y = diff_A485_DMSO, color = density)) +
    geom_point(show.legend = FALSE) + 
    scale_color_viridis() + 
    geom_hline(yintercept = diffCutoff, alpha = 1, color = "black") +
    geom_hline(yintercept = -diffCutoff, alpha = 1, color = "black") +
    geom_vline(xintercept = diffCutoff, alpha = 1, color = "black") +
    geom_vline(xintercept = -diffCutoff, alpha = 1, color = "black") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +coord_fixed(ratio = 1, ylim = c(-1, 1), xlim = c(-1, 1)) + 
    theme_classic()
  
  fileName <- paste0("scatterplot_", name, "_", diffCutoff, "_diff_", loopName, "_dTAG-", diffName)
  png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 3.5, height = 3)
  print(p1)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 3.5, height = 3)
  print(p1)
  dev.off()

Scatterplot & box plot

name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(diff_A485_DMSO > -diffCutoff, "NO", "DOWN")))

makeAcrossSampleScatterplotdTAG <- function(data, AnnoList, diff, name, loopName, diffName){
  temp <- data %>% dplyr::filter(Anno2 %in% AnnoList,
                                 updown_dTAG_DMSO %in% diff)
  temp$density <- get_density(temp$diff_dTAG_DMSO, temp$diff_A485_DMSO, n = 100)
  temp <- temp %>% dplyr::arrange(density)

  p1 <- ggplot(temp, aes(x = diff_dTAG_DMSO, y = diff_A485_DMSO, color = density)) +
    geom_point(show.legend = FALSE) + 
    scale_color_viridis() + 
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +coord_fixed(ratio = 1, ylim = c(-1, 1), xlim = c(-1, 1)) + 
    theme_classic() + ggtitle(paste0(name, "_", loopName, "_dTAG-", diffName)) + theme(plot.title = element_text(size = 5))
  
  fileName <- paste0("scatterplot_", name, "_", diffCutoff, "_diff_", loopName, "_dTAG-", diffName)
  png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 3.5, height = 3)
  print(p1)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 3.5, height = 3)
  print(p1)
  dev.off()
}

makeAcrossSampleScatterplotdTAG(data, unique(data$Anno2), c("UP", "NO", "DOWN"), name, "all", "all")
makeAcrossSampleScatterplotdTAG(data, unique(data$Anno2), c("UP"), name, "all", "UP")
makeAcrossSampleScatterplotdTAG(data, unique(data$Anno2), c("NO"), name, "all", "NO")
makeAcrossSampleScatterplotdTAG(data, unique(data$Anno2), c("DOWN"), name, "all", "DOWN")

makeAcrossSampleScatterplotdTAG(data, c("P-P", "P-E", "E-E"), c("UP", "NO", "DOWN"), name, "pe-pe", "all")
makeAcrossSampleScatterplotdTAG(data, c("P-P", "P-E", "E-E"), c("UP"), name, "pe-pe", "UP")
makeAcrossSampleScatterplotdTAG(data, c("P-P", "P-E", "E-E"), c("NO"), name, "pe-pe", "NO")
makeAcrossSampleScatterplotdTAG(data, c("P-P", "P-E", "E-E"), c("DOWN"), name, "pe-pe", "DOWN")

makeAcrossSampleScatterplotdTAG(data, c("S-S", "S-X"), c("UP", "NO", "DOWN"), name, "str", "all")
makeAcrossSampleScatterplotdTAG(data, c("S-S", "S-X"), c("UP"), name, "str", "UP")
makeAcrossSampleScatterplotdTAG(data, c("S-S", "S-X"), c("NO"), name, "str", "NO")
makeAcrossSampleScatterplotdTAG(data, c("S-S", "S-X"), c("DOWN"), name, "str", "DOWN")

makeAcrossSampleScatterplotA485 <- function(data, AnnoList, diff, name, loopName, diffName){
  temp <- data %>% dplyr::filter(Anno2 %in% AnnoList,
                                 updown_A485_DMSO %in% diff)
  temp$density <- get_density(temp$diff_dTAG_DMSO, temp$diff_A485_DMSO, n = 100)
  temp <- temp %>% dplyr::arrange(density)

  p1 <- ggplot(temp, aes(x = diff_dTAG_DMSO, y = diff_A485_DMSO, color = density)) +
    geom_point(show.legend = FALSE) + 
    scale_color_viridis() + 
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +coord_fixed(ratio = 1, ylim = c(-1, 1), xlim = c(-1, 1)) + 
    theme_classic() + ggtitle(paste0(name, "_", loopName, "_A485G-", diffName)) + theme(plot.title = element_text(size = 5))
  
  fileName <- paste0("scatterplot_", name, "_", diffCutoff, "_diff_", loopName, "_A485-", diffName)
  png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 3.5, height = 3)
  print(p1)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 3.5, height = 3)
  print(p1)
  dev.off()
}

makeAcrossSampleScatterplotA485(data, unique(data$Anno2), c("UP", "NO", "DOWN"), name, "all", "all")
makeAcrossSampleScatterplotA485(data, unique(data$Anno2), c("UP"), name, "all", "UP")
makeAcrossSampleScatterplotA485(data, unique(data$Anno2), c("NO"), name, "all", "NO")
makeAcrossSampleScatterplotA485(data, unique(data$Anno2), c("DOWN"), name, "all", "DOWN")

makeAcrossSampleScatterplotA485(data, c("P-P", "P-E", "E-E"), c("UP", "NO", "DOWN"), name, "pe-pe", "all")
makeAcrossSampleScatterplotA485(data, c("P-P", "P-E", "E-E"), c("UP"), name, "pe-pe", "UP")
makeAcrossSampleScatterplotA485(data, c("P-P", "P-E", "E-E"), c("NO"), name, "pe-pe", "NO")
makeAcrossSampleScatterplotA485(data, c("P-P", "P-E", "E-E"), c("DOWN"), name, "pe-pe", "DOWN")

makeAcrossSampleScatterplotA485(data, c("S-S", "S-X"), c("UP", "NO", "DOWN"), name, "str", "all")
makeAcrossSampleScatterplotA485(data, c("S-S", "S-X"), c("UP"), name, "str", "UP")
makeAcrossSampleScatterplotA485(data, c("S-S", "S-X"), c("NO"), name, "str", "NO")
makeAcrossSampleScatterplotA485(data, c("S-S", "S-X"), c("DOWN"), name, "str", "DOWN")

######## Barplot
temp <- data %>% dplyr::select(updown_dTAG_DMSO, diff_A485_DMSO)
ggplot(temp, aes(x = updown_dTAG_DMSO, y = diff_A485_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))

temp <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E")) %>% dplyr::select(updown_dTAG_DMSO, diff_A485_DMSO) 
ggplot(temp, aes(x = updown_dTAG_DMSO, y = diff_A485_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))


temp <- data %>% dplyr::filter(Anno2 %in% c("S-S", "S-X")) %>% dplyr::select(updown_dTAG_DMSO, diff_A485_DMSO) 
ggplot(temp, aes(x = updown_dTAG_DMSO, y = diff_A485_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))

###
temp <- data %>% dplyr::select(updown_A485_DMSO, diff_dTAG_DMSO)
ggplot(temp, aes(x = updown_A485_DMSO, y = diff_dTAG_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))

temp <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E")) %>% dplyr:::select(updown_A485_DMSO, diff_dTAG_DMSO)
ggplot(temp, aes(x = updown_A485_DMSO, y = diff_dTAG_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))


temp <- data %>% dplyr::filter(Anno2 %in% c("S-S", "S-X")) %>% dplyr:::select(updown_A485_DMSO, diff_dTAG_DMSO)
ggplot(temp, aes(x = updown_A485_DMSO, y = diff_dTAG_DMSO)) + geom_boxplot(outlier.shape = NA) + theme_classic() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = 0.2, linetype = "dashed") +
  geom_hline(yintercept = -0.2, linetype = "dashed") + coord_cartesian(ylim = c(-0.5, 0.5))

[2.29] Compartment analysis

Q. What are the changes in compartment level upon A485 treatment? #### Compartment change distribution

### IMPORTING COMPARMTNET SCORES
compDir <- here("../..", "result", "compartment", "CscoreTools")

cscore.DMSO <- as_tibble(fread(here(compDir, "G1DMSO_Merged_10kb_cscore_final.bedgraph"), skip = 1)) %>%
  dplyr::mutate(V2 = V2 + 1)
colnames(cscore.DMSO) <- c("chr", "start", "end", "cscore_DMSO")

cscore.A485 <- as_tibble(fread(here(compDir, "G1A485_Merged_10kb_cscore_final.bedgraph"), skip = 1)) %>%
  dplyr::mutate(V2 = V2 + 1)
colnames(cscore.A485) <- c("chr", "start", "end", "cscore_A485")


cscore <- dplyr::full_join(cscore.DMSO, cscore.A485, by = c("chr", "start", "end"))

# FILTER ROWS WITH NA
cscore <- cscore %>% filter(!if_any(everything(), is.na))

# Annotating how the compartment changed
threshold <- 0.1
cscore <- cscore %>% rowwise() %>% dplyr::mutate(isAB_DMSO = ifelse(cscore_DMSO > 0, "A", "B"),
                                                 isAB_A485 = ifelse(cscore_A485 > 0, "A", "B"),
                                                 changeType = case_when(
                                                   abs(cscore_DMSO - cscore_A485) < threshold ~ "Unchanged",
                                                   isAB_DMSO == "A" & isAB_A485 == "B" ~ "AtoB",
                                                   isAB_DMSO == "B" & isAB_A485 == "A" ~ "BtoA",
                                                   isAB_DMSO == "A" & isAB_A485 == "A" & abs(cscore_DMSO) > abs(cscore_A485) ~ "A_weakening",
                                                   isAB_DMSO == "A" & isAB_A485 == "A" & abs(cscore_DMSO) <= abs(cscore_A485) ~ "A_strengthening",
                                                   isAB_DMSO == "B" & isAB_A485 == "B" & abs(cscore_DMSO) > abs(cscore_A485) ~ "B_weakening",
                                                   isAB_DMSO == "B" & isAB_A485 == "B" & abs(cscore_DMSO) <= abs(cscore_A485) ~ "B_strengthening"                                                 ))
cscore_summary <- tibble(comparison = rep("A485_vs_DMSO", 7),
                         changeType = c("AtoB", "BtoA", "A_weakening", "A_strengthening", "B_weakening", "B_strengthening", "Unchanged"),
                         value = c(sum(cscore$changeType == "AtoB"),
                                   sum(cscore$changeType == "BtoA"),
                                   sum(cscore$changeType == "A_weakening"),
                                   sum(cscore$changeType == "A_strengthening"),
                                   sum(cscore$changeType == "B_weakening"),
                                   sum(cscore$changeType == "B_strengthening"),
                                   sum(cscore$changeType == "Unchanged")))
cscore_summary$changeType <- factor(cscore_summary$changeType, levels = c("A_weakening", "AtoB", "B_strengthening",
                                                                          "B_weakening", "BtoA", "A_strengthening",
                                                                          "Unchanged"))
ggplot(cscore_summary, aes(x = comparison, y = value, fill = changeType)) + geom_bar(position = "stack", stat = "identity") +
  theme_bw() +
  scale_fill_manual(values = c("skyblue", "blue", "darkblue", "pink", "red2", "darkred" ,"grey"))
  

Combining with RNA-seq

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V1, TSS, V6)
colnames(gene.tb) <- c("chr", "TSS", "ensembl")

diff.RNA <- fread(here(refDir, "diff_G1.A485.selected2_G1.2i.A485_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)
diff.RNA <- diff.RNA %>% dplyr::left_join(gene.tb, by = c("ensembl_gene_id" = "ensembl")) %>%
  dplyr::filter(!is.na(TSS))

alpha <- 0.05
fcCutoff <- 0.5

diff.RNA <- diff.RNA %>% dplyr::mutate(diff = case_when(padj < alpha & shrinked_log2FC > fcCutoff ~ "UP",
                                                        padj < alpha & shrinked_log2FC < -fcCutoff ~ "DOWN",
                                                        TRUE ~ "NO"))


getCompChangeType <- function(chrom, TSS, cscore.tb){
  temp.tb <- cscore.tb %>% dplyr::filter(chr == chrom, start < TSS, end > TSS)
  out <- temp.tb$changeType
  if(length(out) < 1){
    return(NA)
  }else{
    return(out)
  }
}

cscore.gr <- makeGRangesFromDataFrame(cscore[1:3])
temp <-diff.RNA %>% dplyr::mutate(start = TSS, end = TSS +1) %>%
  dplyr::select(chr, start, end)
diff.RNA.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(diff.RNA.gr, cscore.gr)

#cscore.selected <- cscore %>% dplyr::slice(subjectHits(overlap))
## Problem of certain genes not getting overlap with cscore due to sparse calling?
batch1 <- bind_cols(diff.RNA[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


missed <- diff.RNA[-queryHits(overlap)]
temp <- missed %>% dplyr::mutate(TSS = TSS + 10000) %>% dplyr::mutate(start = TSS, end = TSS +1) %>%
  dplyr::select(chr, start, end)
missed.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(missed.gr, cscore.gr)
batch2 <- bind_cols(missed[queryHits(overlap)],
                    data.table(cscore)[subjectHits(overlap)])

missed2 <- missed[-queryHits(overlap)]
temp <- missed2 %>% dplyr::mutate(TSS = TSS - 10000) %>% dplyr::mutate(start = TSS, end = TSS +1) %>%
  dplyr::select(chr, start, end)
missed.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(missed.gr, cscore.gr)
batch3 <- bind_cols(missed2[queryHits(overlap)],
                    data.table(cscore)[subjectHits(overlap)])

#missed3 <- missed2[-queryHits(overlap)]


diff.RNA <- bind_rows(batch1, batch2, batch3)


# VISUALIZE
diff.RNA$changeType <- factor(diff.RNA$changeType, levels = c("A_weakening", "AtoB", "B_strengthening",
                                                                          "B_weakening", "BtoA", "A_strengthening",
                                                                          "Unchanged"))
ggplot(diff.RNA, aes(x = diff, fill = changeType)) +
  geom_bar(position = "fill") +
  labs(title = "Stacked Bar Plot of Change Type by Diff",
       x = "Diff",
       y = "Count") +
  theme_bw() +  scale_fill_manual(values = c("skyblue", "blue", "darkblue", "pink", "red2", "darkred" ,"grey"))

Combining with loop

name <- "chromo_cons_annoHierarchy"

# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_UP_diff0.2.bedpe"))
anchor.up <- (extractAnchor(loop.up))
anchor.up.tb <- as_tibble(anchor.up) %>%
  dplyr::mutate(center = (start + end)/2) %>%
  dplyr::mutate(start = center-1, end = center+1) %>%
  dplyr::select(seqnames, start, end)
anchor.up <- makeGRangesFromDataFrame(anchor.up.tb)
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_NO_diff0.2.bedpe"))
anchor.no <- (extractAnchor(loop.no))
anchor.no.tb <- as_tibble(anchor.no) %>%
  dplyr::mutate(center = (start + end)/2) %>%
  dplyr::mutate(start = center-1, end = center+1) %>%
  dplyr::select(seqnames, start, end)
anchor.no <- makeGRangesFromDataFrame(anchor.no.tb)
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_A485vsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- (extractAnchor(loop.down))
anchor.down.tb <- as_tibble(anchor.down) %>%
  dplyr::mutate(center = (start + end)/2) %>%
  dplyr::mutate(start = center-1, end = center+1) %>%
  dplyr::select(seqnames, start, end)
anchor.down <- makeGRangesFromDataFrame(anchor.down.tb)


########################################################################
### Overlap
cscore.gr <- makeGRangesFromDataFrame(cscore[1:3])
overlap <- findOverlaps(anchor.up, cscore.gr)

## Problem of certain genes not getting overlap with cscore due to sparse calling?
batch1 <- bind_cols(data.table(anchor.up.tb)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


missed <- data.table(anchor.up.tb)[-queryHits(overlap)]
temp <- missed %>% dplyr::mutate(start = start - 10000, end = end - 10000) %>%
  dplyr::select(seqnames, start, end)
missed.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(missed.gr, cscore.gr)
batch2 <- bind_cols((missed)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


data.up <- bind_rows(batch1, batch2)

########################################################################
### Overlap
cscore.gr <- makeGRangesFromDataFrame(cscore[1:3])
overlap <- findOverlaps(anchor.no, cscore.gr)

## Problem of certain genes not getting overlap with cscore due to sparse calling?
batch1 <- bind_cols(data.table(anchor.no.tb)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


missed <- data.table(anchor.no.tb)[-queryHits(overlap)]
temp <- missed %>% dplyr::mutate(start = start - 10000, end = end - 10000) %>%
  dplyr::select(seqnames, start, end)
missed.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(missed.gr, cscore.gr)
batch2 <- bind_cols((missed)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


data.no <- bind_rows(batch1, batch2)

########################################################################
### Overlap
cscore.gr <- makeGRangesFromDataFrame(cscore[1:3])
overlap <- findOverlaps(anchor.down, cscore.gr)

## Problem of certain genes not getting overlap with cscore due to sparse calling?
batch1 <- bind_cols(data.table(anchor.down.tb)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


missed <- data.table(anchor.down.tb)[-queryHits(overlap)]
temp <- missed %>% dplyr::mutate(start = start - 10000, end = end - 10000) %>%
  dplyr::select(seqnames, start, end)
missed.gr <- makeGRangesFromDataFrame(temp)
overlap <- findOverlaps(missed.gr, cscore.gr)
batch2 <- bind_cols((missed)[queryHits(overlap)],
          data.table(cscore)[subjectHits(overlap)])


data.down <- bind_rows(batch1, batch2)

n.up <- nrow(data.up)
n.no <- nrow(data.no)
n.down <- nrow(data.down)

data <- tibble(loopDiff = c(rep("UP", n.up), rep("NO", n.no), rep("DOWN", n.down)),
              changeType = c(data.up$changeType, data.no$changeType, data.down$changeType))

# VISUALIZE
data$changeType <- factor(data$changeType, levels = c("A_weakening", "AtoB", "B_strengthening",
                                                                          "B_weakening", "BtoA", "A_strengthening",
                                                                          "Unchanged"))
ggplot(data, aes(x = loopDiff, fill = changeType)) +
  geom_bar(position = "fill") +
  labs(title = "Stacked Bar Plot of Change Type by Diff",
       x = "Diff",
       y = "Count") +
  theme_bw() +  scale_fill_manual(values = c("skyblue", "blue", "darkblue", "pink", "red2", "darkred" ,"grey"))

[2.30] ChromHMM

resultDir <- here("../../result")

data <- fread(here(resultDir, "chromHMM", "A485_pe-pe_anchors", "overlap_enrich_100_state.txt"))
colnames(data) <- c("state", "genome", "pe-pe_A485_down", "pe-pe_A485_no", "pe-pe_A485_up")
data <- data %>% dplyr::select(-genome)

data_matrix <- data %>%
  column_to_rownames(var = "state") %>%
  as.matrix()

library(circlize)

col_fun <- colorRamp2(c(0, 1, 10), 
                      c("blue", "white", "red"))

Heatmap(
  data_matrix,
  name = "Value",
  show_row_names = TRUE,
  show_column_names = TRUE,
  cluster_columns = FALSE,
  cluster_rows = FALSE,
   col = col_fun
)

#######
data2 <- data %>% dplyr::select(c(1, 2, 4))
data2 <- data2 %>% dplyr::filter(`pe-pe_A485_down` > `pe-pe_A485_up`)
data_matrix <- data2 %>%
  column_to_rownames(var = "state") %>%
  as.matrix()

library(circlize)

col_fun <- colorRamp2(c(0, 1, 10), 
                      c("blue", "white", "red"))

Heatmap(
  data_matrix,
  name = "Value",
  show_row_names = TRUE,
  show_column_names = TRUE,
  cluster_columns = FALSE,
  cluster_rows = FALSE,
   col = col_fun
)

[2.31] Making Visualization Easy

https://bioconductor.org/books/devel/OHCA/pages/visualization.html

### Getting loop ID
temp <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>%
  dplyr::mutate(res = V3 - V2,
                id = paste(V1, res, V2, V5, sep = "_"))
regID <- temp$id

temp <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>%
  dplyr::mutate(res = V3 - V2,
                id = paste(V1, res, V2, V5, sep = "_"))
strID <- temp$id

############## REG
## Filtering loops to plot
data <- fread(here(consensusDir, "chromo_cons_score.tsv"))
temp <- data %>% dplyr::filter(id %in% regID, dTAG > 0.5) %>% dplyr::arrange(desc(dTAG))
temp <- temp %>% dplyr::select(seq(1, 6))
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loops <- importBedpe(temp)

# Visualization
hicDir <- "/Volumes/UKJIN_SSD/data_vault_2024summer_microC/hic"
windowSize <- 1*1e6

i = 1
# for(i in seq(1, 25)){
  ## Loading hic and plotting
  chr <- as_tibble(loops[i])$seqnames1
  center <- (as_tibble(loops[i])$start1 + as_tibble(loops[i])$end2)/2
  start <- floor(center - 0.5*windowSize)
  end <- floor(center + 0.5*windowSize)
  
  cf.G1DMSO <- HicFile(path = here(hicDir, "G1.DMSO.Merged.hic"))
  cf.G1dTAG <- HicFile(path = here(hicDir, "G1.dTAG.Merged.hic"))
  #cf.G1dTAG <- HicFile(path = here(hicDir, "G1.A485.Merged.hic"))

  res <- 10*1000
  zmax <- 2.5
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_regLoop_dTAG_", i, "_10kb_figureVer"))
  
  width <- panelSize(20)*mmToInch
  height <- panelSize(10)*mmToInch
  
  png(paste0(fileName, ".png"), res = 600, units = "in", width = width, height = height)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  svglite(paste0(fileName, ".svg"), width = width, height = height)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  
  res <- 25*1000
  zmax <- 3
  start <- floor(center - windowSize)
  end <- floor(center + windowSize)
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_regLoop_dTAG_", i, "_25kb"))
  png(paste0(fileName, ".png"), res = 600, units = "in", width = 10, height = 5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  # svglite(paste0(fileName, ".svg"), width = 10, height = 5)
  # print(cowplot::plot_grid(p1, p2, align = "h"))
  # dev.off()
# }

############## Str
## Filtering loops to plot
data <- fread(here(consensusDir, "chromo_cons_score.tsv"))
temp <- data %>% dplyr::filter(id %in% strID, dTAG > 0.5) %>% dplyr::arrange(desc(dTAG))
temp <- temp %>% dplyr::select(seq(1, 6))
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loops <- importBedpe(temp)

# Visualization
hicDir <- "/Volumes/UKJIN_SSD/Genomics_03_Analysis_Working/data_vault_2024summer_microC/hic"
windowSize <- 2*1e6

for(i in seq(1, 25)){
  ## Loading hic and plotting
  chr <- as_tibble(loops[i])$seqnames1
  center <- (as_tibble(loops[i])$start1 + as_tibble(loops[i])$end2)/2
  start <- floor(center - 0.5*windowSize)
  end <- floor(center + 0.5*windowSize)
  
  cf.G1DMSO <- HicFile(path = here(hicDir, "G1.DMSO.Merged.hic"))
  cf.G1dTAG <- HicFile(path = here(hicDir, "G1.dTAG.Merged.hic"))

  res <- 10*1000
  zmax <- 2.5
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_strLoop_dTAG_", i, "_10kb"))
  png(paste0(fileName, ".png"), res = 600, units = "in", width = 10, height = 5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  
  
  res <- 25*1000
  zmax <- 3
  start <- floor(center - windowSize)
  end <- floor(center + windowSize)
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_strLoop_dTAG_", i, "_25kb"))
  png(paste0(fileName, ".png"), res = 600, units = "in", width = 10, height = 5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
}

############## dTAG called loops
## Filtering loops to plot
data1 <- fread(here(loopDir, "G1.dTAG.Merged_chromosight_25kb.tsv"))
data2 <- fread(here(loopDir, "G1.dTAG.Merged_chromosight_10kb.tsv"))
data3 <- fread(here(loopDir, "G1.dTAG.Merged_chromosight_5kb.tsv"))
data <- bind_rows(data1, data2, data3)

temp <- data %>% dplyr::arrange(desc(score))

temp <- temp %>% dplyr::select(seq(1, 6))
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
loops <- importBedpe(temp)

# Visualization
hicDir <- "/Volumes/UKJIN_SSD/Genomics_03_Analysis_Working/data_vault_2024summer_microC/hic"
windowSize <- 2*1e6

for(i in seq(1, 25)){
  ## Loading hic and plotting
  chr <- as_tibble(loops[i])$seqnames1
  center <- (as_tibble(loops[i])$start1 + as_tibble(loops[i])$end2)/2
  start <- floor(center - 0.5*windowSize)
  end <- floor(center + 0.5*windowSize)
  
  cf.G1DMSO <- HicFile(path = here(hicDir, "G1.DMSO.Merged.hic"))
  cf.G1dTAG <- HicFile(path = here(hicDir, "G1.dTAG.Merged.hic"))

  res <- 10*1000
  zmax <- 2.5
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_dTAGcalledLoop_dTAG_", i, "_10kb"))
  png(paste0(fileName, ".png"), res = 600, units = "in", width = 10, height = 5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  
  
  res <- 25*1000
  zmax <- 3
  start <- floor(center - windowSize)
  end <- floor(center + windowSize)
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax), loop = loops)
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax), loop = loops)
  
  fileName <- here(figDir, paste0("visuzliation_dTAGcalledLoop_dTAG_", i, "_25kb"))
  png(paste0(fileName, ".png"), res = 600, units = "in", width = 10, height = 5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
}

chr = "chr13"
start = 96900000
end = 98100000
  res <- 10*1000
  zmax <- 2.5
  hic1 <- import(cf.G1DMSO, focus = paste0(chr, ":", start, "-", end), resolution = res)
  hic2 <- import(cf.G1dTAG, focus = paste0(chr, ":", start, "-", end), resolution = res)
  p1 <- plotMatrix(hic1, dpi = 1000, limits = c(0, zmax))
  p2 <- plotMatrix(hic2, dpi = 1000, limits = c(0, zmax))
    print(cowplot::plot_grid(p1, p2, align = "h"))

[2.32] Heatmap of loops

Strategy: check overlap of the union loops to the loops called at each condition #### Check sample specific called loops

library(circlize)

name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
temp <- data %>% dplyr::select(seq(1, 6))
colnames(temp) <- c("V1", "V2", "V3", "V4", "V5", "V6")
cons.loop <- importBedpe(temp)

# Checking DMSO
loop.25kb <- importBedpe(fread(here(loopDir, paste0("G1.DMSO.Merged_chromosight_", 25, "kb.bedpe"))))
loop.10kb <- importBedpe(fread(here(loopDir, paste0("G1.DMSO.Merged_chromosight_", 10, "kb.bedpe"))))
loop.5kb <- importBedpe(fread(here(loopDir, paste0("G1.DMSO.Merged_chromosight_", 5, "kb.bedpe"))))


overlap.25kb <- findOverlaps(cons.loop, loop.25kb)
overlap.10kb <- findOverlaps(cons.loop, loop.10kb)
overlap.5kb <- findOverlaps(cons.loop, loop.5kb)

index <- sort(unique(c(queryHits(overlap.25kb),
         queryHits(overlap.10kb),
         queryHits(overlap.5kb))))
data$calledByDMSO <- 0
data$calledByDMSO[index] <- 1

# Checking dTAG
loop.25kb <- importBedpe(fread(here(loopDir, paste0("G1.dTAG.Merged_chromosight_", 25, "kb.bedpe"))))
loop.10kb <- importBedpe(fread(here(loopDir, paste0("G1.dTAG.Merged_chromosight_", 10, "kb.bedpe"))))
loop.5kb <- importBedpe(fread(here(loopDir, paste0("G1.dTAG.Merged_chromosight_", 5, "kb.bedpe"))))


overlap.25kb <- findOverlaps(cons.loop, loop.25kb)
overlap.10kb <- findOverlaps(cons.loop, loop.10kb)
overlap.5kb <- findOverlaps(cons.loop, loop.5kb)

index <- sort(unique(c(queryHits(overlap.25kb),
         queryHits(overlap.10kb),
         queryHits(overlap.5kb))))
data$calledBydTAG <- 0
data$calledBydTAG[index] <- 1

# Checking A485
loop.25kb <- importBedpe(fread(here(loopDir, paste0("G1.A485.Merged_chromosight_", 25, "kb.bedpe"))))
loop.10kb <- importBedpe(fread(here(loopDir, paste0("G1.A485.Merged_chromosight_", 10, "kb.bedpe"))))
loop.5kb <- importBedpe(fread(here(loopDir, paste0("G1.A485.Merged_chromosight_", 5, "kb.bedpe"))))


overlap.25kb <- findOverlaps(cons.loop, loop.25kb)
overlap.10kb <- findOverlaps(cons.loop, loop.10kb)
overlap.5kb <- findOverlaps(cons.loop, loop.5kb)

index <- sort(unique(c(queryHits(overlap.25kb),
         queryHits(overlap.10kb),
         queryHits(overlap.5kb))))
data$calledByA485 <- 0
data$calledByA485[index] <- 1


# Heatmap (checking whether certain peak is called by specific sample)
dataToPlot <- data %>% dplyr::select(id, calledByDMSO, calledBydTAG, calledByA485)
dataToPlot <- dataToPlot %>% dplyr::mutate(flag = 4*calledByDMSO + 2*calledBydTAG + calledByA485) %>%
  dplyr::arrange(desc(flag))

row_groups <- dataToPlot$flag
data_matrix <- dataToPlot %>% column_to_rownames(var = "id") %>% dplyr::select(-flag) %>% as.matrix()
col_fun <- colorRamp2(c(0, 1), 
                      c("white", "green"))
h1 <- Heatmap(data_matrix, name = "calledBy",
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_row_dend = FALSE,
        border = TRUE,
        show_row_names = FALSE,
        col = col_fun,
        row_split = row_groups)


# Prepare data for the second heatmap
dataToPlot2 <- data %>% dplyr::select(id, DMSO, dTAG, A485) %>%
  arrange(match(id, dataToPlot$id))

data_matrix2 <- dataToPlot2 %>% column_to_rownames(var = "id") %>% as.matrix()


col_fun2 <- colorRamp2(c(-0.5, 0, 1), c("blue", "white", "red"))

h2 <- Heatmap(data_matrix2, name = "score",
              cluster_columns = FALSE,
              cluster_rows = TRUE,
              show_row_dend = FALSE,
              border = TRUE,
              show_row_names = FALSE,
              col = col_fun2,
              row_split = row_groups)


fileName <- here(figDir, paste0("heatmap_checkingSampleCalledLoops"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 3, height = 10)
print(h1 + h2)
dev.off()

Checking updown

All loops
# Heatmap
library(circlize)

# Heatmap 2
set.seed(123)

diffCutoff <- 0.2
dataToPlot <- data %>% dplyr::mutate(isdiff_dTAG_DMSO = 
                                       case_when(diff_dTAG_DMSO >= diffCutoff ~ 1,
                                                 abs(diff_dTAG_DMSO) < diffCutoff ~ 0,
                                                 diff_dTAG_DMSO <= -diffCutoff ~ -1,
                                                 TRUE ~ NA),
                                     isdiff_A485_DMSO = 
                                       case_when(diff_A485_DMSO >= diffCutoff ~ 1,
                                                 abs(diff_A485_DMSO) < diffCutoff ~ 0,
                                                 diff_A485_DMSO <= -diffCutoff ~ -1,
                                                 TRUE ~ NA)) %>%
  dplyr::select(id, isdiff_dTAG_DMSO, isdiff_A485_DMSO)
data_matrix <- dataToPlot %>% column_to_rownames(var = "id")%>% as.matrix()
col_fun <- colorRamp2(c(-1, 0, 1), c("blue", "grey", "red"))
h1 <- Heatmap(data_matrix, name = "loop score",
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        row_km = 9,
        show_row_dend = FALSE,
        border = FALSE,
        show_row_names = FALSE,
        col = col_fun)

fileName <- here(figDir, paste0("heatmap_checkingDeltaAcrossCondition"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 2, height = 10)
print(h1)
dev.off()

set.seed(123)

hm_drawn <- draw(h1)
row_clusters <- row_order(hm_drawn)

loop.cluster1 <- temp[row_clusters[[1]]]
loop.cluster2 <- temp[row_clusters[[2]]]
loop.cluster3 <- temp[row_clusters[[3]]]
loop.cluster4 <- temp[row_clusters[[4]]]
loop.cluster5 <- temp[row_clusters[[5]]]
loop.cluster6 <- temp[row_clusters[[6]]]
loop.cluster7 <- temp[row_clusters[[7]]]
loop.cluster8 <- temp[row_clusters[[8]]]
loop.cluster9 <- temp[row_clusters[[9]]]
Reg loops
# Heatmap
library(circlize)

# Heatmap 2
set.seed(123)

diffCutoff <- 0.2
dataToPlot <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E")) %>%
  dplyr::mutate(isdiff_dTAG_DMSO = 
                  case_when(diff_dTAG_DMSO >= diffCutoff ~ 1,
                            abs(diff_dTAG_DMSO) < diffCutoff ~ 0,
                            diff_dTAG_DMSO <= -diffCutoff ~ -1,
                            TRUE ~ NA),
                isdiff_A485_DMSO = 
                  case_when(diff_A485_DMSO >= diffCutoff ~ 1,
                            abs(diff_A485_DMSO) < diffCutoff ~ 0,
                            diff_A485_DMSO <= -diffCutoff ~ -1,
                            TRUE ~ NA)) %>%
  dplyr::select(id, isdiff_dTAG_DMSO, isdiff_A485_DMSO)
data_matrix <- dataToPlot %>% column_to_rownames(var = "id")%>% as.matrix()
col_fun <- colorRamp2(c(-1, 0, 1), c("blue", "grey", "red"))
h1 <- Heatmap(data_matrix, name = "loop score",
              cluster_columns = FALSE,
              cluster_rows = FALSE,
        row_km = 8,
        show_row_dend = FALSE,
        border = FALSE,
        show_row_names = FALSE,
        col = col_fun)

fileName <- here(figDir, paste0("heatmap_checkingDeltaAcrossCondition_reg"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 2, height = 10)
print(h1)
dev.off()

set.seed(123)

hm_drawn <- draw(h1)
row_clusters <- row_order(hm_drawn)

loop.cluster1 <- temp[row_clusters[[1]]]
loop.cluster2 <- temp[row_clusters[[2]]]
loop.cluster3 <- temp[row_clusters[[3]]]
loop.cluster4 <- temp[row_clusters[[4]]]
loop.cluster5 <- temp[row_clusters[[5]]]
loop.cluster6 <- temp[row_clusters[[6]]]
loop.cluster7 <- temp[row_clusters[[7]]]
loop.cluster8 <- temp[row_clusters[[8]]]
library(circlize)

set.seed(123)
dataToPlot <- data %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E")) %>%
  dplyr::select(id, diff_dTAG_DMSO, diff_A485_DMSO)
data_matrix <- dataToPlot %>% column_to_rownames(var = "id")%>% as.matrix()
col_fun <- colorRamp2(c(-1, 0, 1), c("blue", "white", "red"))
h1 <- Heatmap(data_matrix, name = "loop score",
              cluster_columns = FALSE,
              cluster_rows = FALSE,
        row_km = 4,
        show_row_dend = FALSE,
        border = TRUE,
        show_row_names = FALSE,
        col = col_fun)


fileName <- here(figDir, paste0("heatmap_diffScore_reg_k4"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 2, height = 6)
print(h1)
dev.off()

hm_drawn <- draw(h1)
row_clusters <- row_order(hm_drawn)

loop.cluster1 <- temp[row_clusters[[1]]]
loop.cluster2 <- temp[row_clusters[[2]]]
loop.cluster3 <- temp[row_clusters[[3]]]
loop.cluster4 <- temp[row_clusters[[4]]]
All loops _OE
# Heatmap
library(circlize)

name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
# Heatmap 2
set.seed(123)

# Import obs/exp scores and merge to the dataset
minValue <- -4
diffCutoff <- 0.5
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))


# Merge dataset
dataToPlot <- data %>% dplyr::left_join(obsexp, by = c("id")) %>%
  dplyr::mutate(log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO,
                isdiff_dTAG_DMSO = case_when(log_obsexp_diff_dTAG_DMSO >= diffCutoff ~ 1,
                                             abs(log_obsexp_diff_dTAG_DMSO) < diffCutoff ~ 0,
                                             log_obsexp_diff_dTAG_DMSO <= diffCutoff ~ -1,
                                             TRUE ~ NA ),
                isdiff_A485_DMSO = case_when(log_obsexp_diff_A485_DMSO >= diffCutoff ~ 1,
                                             abs(log_obsexp_diff_A485_DMSO) < diffCutoff ~ 0,
                                             log_obsexp_diff_A485_DMSO <= diffCutoff ~ -1,
                                             TRUE ~ NA))%>%
  dplyr::select(id, isdiff_dTAG_DMSO, isdiff_A485_DMSO)



data_matrix <- dataToPlot %>% column_to_rownames(var = "id")%>% as.matrix()
col_fun <- colorRamp2(c(-1, 0, 1), c("blue", "grey", "red"))
h1 <- Heatmap(data_matrix, name = "loop score",
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        row_km = 9,
        show_row_dend = FALSE,
        border = FALSE,
        show_row_names = FALSE,
        col = col_fun)

fileName <- here(figDir, paste0("heatmap_checkingDeltaAcrossCondition_OE"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 2, height = 10)
print(h1)
dev.off()
# 
# set.seed(123)
# 
# hm_drawn <- draw(h1)
# row_clusters <- row_order(hm_drawn)
# 
# loop.cluster1 <- temp[row_clusters[[1]]]
# loop.cluster2 <- temp[row_clusters[[2]]]
# loop.cluster3 <- temp[row_clusters[[3]]]
# loop.cluster4 <- temp[row_clusters[[4]]]
# loop.cluster5 <- temp[row_clusters[[5]]]
# loop.cluster6 <- temp[row_clusters[[6]]]
# loop.cluster7 <- temp[row_clusters[[7]]]
# loop.cluster8 <- temp[row_clusters[[8]]]
# loop.cluster9 <- temp[row_clusters[[9]]]
Reg loops _OE
# Heatmap
library(circlize)

name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))
# Heatmap 2
set.seed(123)

# Import obs/exp scores and merge to the dataset
minValue <- -4
diffCutoff <- 0.5
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))


# Merge dataset
dataToPlot <- data %>% dplyr::left_join(obsexp, by = c("id")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E")) %>%
  dplyr::mutate(log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO,
                isdiff_dTAG_DMSO = case_when(log_obsexp_diff_dTAG_DMSO >= diffCutoff ~ 1,
                                             abs(log_obsexp_diff_dTAG_DMSO) < diffCutoff ~ 0,
                                             log_obsexp_diff_dTAG_DMSO <= diffCutoff ~ -1,
                                             TRUE ~ NA ),
                isdiff_A485_DMSO = case_when(log_obsexp_diff_A485_DMSO >= diffCutoff ~ 1,
                                             abs(log_obsexp_diff_A485_DMSO) < diffCutoff ~ 0,
                                             log_obsexp_diff_A485_DMSO <= diffCutoff ~ -1,
                                             TRUE ~ NA))%>%
  dplyr::select(id, isdiff_dTAG_DMSO, isdiff_A485_DMSO)



data_matrix <- dataToPlot %>% column_to_rownames(var = "id")%>% as.matrix()
col_fun <- colorRamp2(c(-1, 0, 1), c("blue", "grey", "red"))
h1 <- Heatmap(data_matrix, name = "loop score",
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        row_km = 9,
        show_row_dend = FALSE,
        border = FALSE,
        show_row_names = FALSE,
        col = col_fun)

fileName <- here(figDir, paste0("heatmap_checkingDeltaAcrossCondition_reg_OE"))
png(paste0(fileName, ".png"), res = 600, units = "in", width = 2, height = 10)
print(h1)
dev.off()
# 
# set.seed(123)
# 
# hm_drawn <- draw(h1)
# row_clusters <- row_order(hm_drawn)
# 
# loop.cluster1 <- temp[row_clusters[[1]]]
# loop.cluster2 <- temp[row_clusters[[2]]]
# loop.cluster3 <- temp[row_clusters[[3]]]
# loop.cluster4 <- temp[row_clusters[[4]]]
# loop.cluster5 <- temp[row_clusters[[5]]]
# loop.cluster6 <- temp[row_clusters[[6]]]
# loop.cluster7 <- temp[row_clusters[[7]]]
# loop.cluster8 <- temp[row_clusters[[8]]]
# loop.cluster9 <- temp[row_clusters[[9]]]

[2.32] Comparing with Bobbie’s data

Where does differentiated related genes fall into?

marginError <- function(myList) {
  sample.n = length(myList)
  sample.sd = sd(myList)
  sample.se = sample.sd/sqrt(sample.n)
  alpha = 0.05
  degrees.freedom = sample.n - 1
  t.score = qt(p = alpha/2, df = degrees.freedom, lower.tail = F)
  margin.error = t.score*sample.se
  return(margin.error)
}

PROseq.bobbie <- as_tibble(fread(here(refDir, "bobbie_gene_classification.csv")))

geneList.Epi.dTAG.up <- (fread(here(refDir, "diff_G1.dTAG_G1.Epi.dTAG_vs_G1.Epi.DMSO.tsv")) %>% dplyr::filter(padj < 0.05, log2FoldChange > 0))$ensembl_gene_id

geneList.Epi.dTAG.down <- (fread(here(refDir, "diff_G1.dTAG_G1.Epi.dTAG_vs_G1.Epi.DMSO.tsv")) %>% dplyr::filter(padj < 0.05, log2FoldChange < 0))$ensembl_gene_id

## Converting transcript ID to gene ID
idPair_tg <- getBM(attributes = c("ensembl_transcript_id", "ensembl_gene_id"),
                 filters = "ensembl_transcript_id",
                 values = PROseq.bobbie$enst,
                 mart = ensembl.v102)
PROseq.bobbie <- PROseq.bobbie %>% dplyr::left_join(idPair_tg, by = c("enst" = "ensembl_transcript_id"))

## Bar Plot
temp <- PROseq.bobbie %>% dplyr::filter(ensembl_gene_id %in% geneList.Epi.dTAG.down)

group <- c(rep("EpiLC_dTAGvsDMSO_DOWN", 4))
cluster <- rep(c("Early", "Middle", "Late", "Transient"), 1)
cluster <- factor(cluster, levels = c("Early", "Middle", "Late", "Transient"))
value <- c(sum(temp$Cluster == "Early"),
           sum(temp$Cluster == "Middle"),
           sum(temp$Cluster == "Late"),
           sum(temp$Cluster == "Transient"))
data <- data.frame(group, cluster, value)
ggplot(data, aes(fill=cluster, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()

## Line plot
temp <- temp %>% dplyr::select(c(4, 5, 6, 7, 8, 9))
temp.tall = temp %>% pivot_longer(-c(1, 2), names_to = "timepoints", values_to = "value")

gg1 = ggplot(temp.tall,
       aes( x = factor(timepoints, level = c("MIT", "EG1", "LG1", "ASYN")),
            y = value,
            group = enst, col = enst)) +
  geom_line() +
  theme_classic() +
  ggtitle("Bobbie, PRO-seq", subtitle = "selected genes") +
  xlab ("timepoints") + ylab("value") +
  theme(plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "none",
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

ggsave(filename = here(figDir, "bobbie_gene_EpiLC_dTAGvsDMSO_DOWN.png"), gg1, width = 4, height = 4, dpi = 300, units = "in", device = "png")


# DRAW RIBBON


temp.ribbon = tibble("timepoints" = c("MIT", "EG1", "LG1", "ASYN"),
                      "value" = c(mean(temp$MIT), mean(temp$EG1), mean(temp$LG1), mean(temp$ASYN)),
                      "lower" = c(mean(temp$MIT) - marginError(temp$MIT), 
                                  mean(temp$EG1) - marginError(temp$EG1), 
                                  mean(temp$LG1) - marginError(temp$LG1), 
                                  mean(temp$ASYN) - marginError(temp$ASYN)),
                      "upper" = c(mean(temp$MIT) + marginError(temp$MIT), 
                                  mean(temp$EG1) + marginError(temp$EG1), 
                                  mean(temp$LG1) + marginError(temp$LG1), 
                                  mean(temp$ASYN) + marginError(temp$ASYN)))
gg1 = ggplot(temp.ribbon, aes(x = factor(timepoints, level = c("MIT", "EG1", "LG1", "ASYN")), 
                        y = value, group = 1)) +
  geom_line(color = "black") +
  geom_ribbon(aes(ymin = lower, ymax = upper), fill = "grey70", alpha = 0.3) +
  theme_classic() +
  ggtitle("Bobbie, PRO-seq", subtitle = "selected genes") +
  xlab ("timepoints") + ylab("value") + ylim(0, 65) +
  theme(plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "none",
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

ggsave(filename = here(figDir, "bobbie_gene_EpiLC_dTAGvsDMSO_DOWN_95CI.png"), gg1, width = 4, height = 4, dpi = 300, units = "in", device = "png")

###[2.33] Finding closest enhancer Here, enhancer will be defined by H3K27ac peak It makes more sence to include the enhancer peak on gene body (strategy 1) exclude +-10kb region from TSS only (strategy 2) only check the E-P loops called in Micro-C ##### binary group - excluding all gene body

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3), ensembl = V6, chr = V1) %>%
  dplyr::select(ensembl, chr, TSS)

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.tb <- gene.tb %>% dplyr::filter(ensembl %in% c(group1, group2))
genes.gr <- GRanges(
  seqnames = gene.tb$chr,
  ranges = IRanges(start = gene.tb$TSS, end = gene.tb$TSS),
  ensembl = gene.tb$ensembl
)

genebody.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>% dplyr::select(V1, V2, V3)
colnames(genebody.tb) <- c("chr", "start", "end")
genebody.gr <- makeGRangesFromDataFrame(genebody.tb)


peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
peak.H3K27ac<- makeGRangesFromDataFrame(fread(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed")) %>% 
                                          dplyr::mutate(chr = V1, start = (V2 + V3)/2, end = (V2 + V3)/2) %>%
                                          dplyr::select(chr, start, end))

####### Filtering out peaks overlapping with the gene body
overlaps <- findOverlaps(genebody.gr, peak.H3K27ac)

# Indices of peaks that overlap the TSS
overlapping_peak_indices <- unique(subjectHits(overlaps))

# Exclude overlapping peaks
non_overlapping_peaks <- peak.H3K27ac[-overlapping_peak_indices]


####### Calculating distance to nearest peak
nearest_peak_indices <- nearest(genes.gr, non_overlapping_peaks)
nearest_peaks <- non_overlapping_peaks[nearest_peak_indices]
distances <- distance(genes.gr, nearest_peaks)


results <- data.frame(
  ensembl = mcols(genes.gr)$ensembl,
  gene_chr = as.character(seqnames(genes.gr)),
  gene_TSS = start(genes.gr),
  peak_chr = as.character(seqnames(nearest_peaks)),
  peak_start = start(nearest_peaks),
  peak_end = end(nearest_peaks),
  distance = distances
)

results <- results %>% dplyr::mutate(group = case_when(ensembl %in% group1 ~ "group1",
                                            ensembl %in% group2 ~ "group2",
                                            TRUE ~ NA))

ggplot(results, aes(x = group, y = distance, fill = group)) + geom_violin() + geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") + theme_bw() + ggtitle("distance to nearest H3K27ac peak excluding gene body") + scale_y_continuous(labels = label_kb_mb) + coord_cartesian(ylim = c(0, 250*1000))

  
binary group - excluding specific gene body
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3), ensembl = V6, chr = V1) %>%
  dplyr::select(ensembl, chr, TSS) %>% dplyr::filter(ensembl %in% c(group1, group2))
genes.gr <- GRanges(
  seqnames = gene.tb$chr,
  ranges = IRanges(start = gene.tb$TSS, end = gene.tb$TSS),
  ensembl = gene.tb$ensembl
)

genebody.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>% dplyr::filter(V6 %in% c(group1, group2))%>% dplyr::select(V1, V2, V3)
colnames(genebody.tb) <- c("chr", "start", "end")
genebody.gr <- makeGRangesFromDataFrame(genebody.tb)


# Step 1: Find overlaps between gene bodies and peaks
overlaps <- findOverlaps(genebody.gr, peak.H3K27ac)

# Create a list mapping each gene to the indices of peaks overlapping with its gene body
overlapping_peaks_per_gene <- split(subjectHits(overlaps), queryHits(overlaps))

# Initialize an empty list to store results
results_list <- vector("list", length(genes.gr))

# Step 2: For each gene, exclude overlapping peaks and find the nearest peak to its TSS
for (i in seq_along(genes.gr)) {
  gene <- genes.gr[i]
  
  # Get indices of peaks overlapping with this gene's body
  overlapping_peak_indices <- overlapping_peaks_per_gene[[as.character(i)]]
  
  # Exclude overlapping peaks for this gene
  if (!is.null(overlapping_peak_indices)) {
    peaks_to_consider <- peak.H3K27ac[-overlapping_peak_indices]
  } else {
    peaks_to_consider <- peak.H3K27ac
  }
  
  # Find the nearest peak to the TSS of this gene
  nearest_peak_index <- nearest(gene, peaks_to_consider)
  
  if (is.na(nearest_peak_index)) {
    # No peaks found; set NA values
    results_list[[i]] <- data.frame(
      ensembl = mcols(gene)$ensembl,
      gene_chr = as.character(seqnames(gene)),
      gene_TSS = start(gene),
      peak_chr = NA,
      peak_start = NA,
      peak_end = NA,
      distance = NA
    )
  } else {
    nearest_peak <- peaks_to_consider[nearest_peak_index]
    dist <- distance(gene, nearest_peak)
    
    results_list[[i]] <- data.frame(
      ensembl = mcols(gene)$ensembl,
      gene_chr = as.character(seqnames(gene)),
      gene_TSS = start(gene),
      peak_chr = as.character(seqnames(nearest_peak)),
      peak_start = start(nearest_peak),
      peak_end = end(nearest_peak),
      distance = dist
    )
  }
}

# Combine results into a single data frame
results <- do.call(rbind, results_list)

# Add group information
results <- results %>% dplyr::mutate(group = case_when(
  ensembl %in% group1 ~ "group1",
  ensembl %in% group2 ~ "group2",
  TRUE ~ NA_character_
))

# Plotting
ggplot(results, aes(x = group, y = distance, fill = group)) +
  geom_violin() +
  geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") +
  theme_bw() +
  ggtitle("Distance to Nearest H3K27ac Peak Excluding Gene Body Overlaps") +
  scale_y_continuous(labels = label_kb_mb) +
  coord_cartesian(ylim = c(0, 50 * 1000))
binary group - excluding all TSS +- 10kb
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3), ensembl = V6, chr = V1) %>%
  dplyr::select(ensembl, chr, TSS)

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.tb <- gene.tb %>% dplyr::filter(ensembl %in% c(group1, group2))
genes.gr <- GRanges(
  seqnames = gene.tb$chr,
  ranges = IRanges(start = gene.tb$TSS, end = gene.tb$TSS),
  ensembl = gene.tb$ensembl
)

genebody.tb <- gene.tb %>% dplyr::mutate(start = TSS-10*1000, end = TSS + 10*1000) %>%
  dplyr::select(chr, start, end)

genebody.gr <- makeGRangesFromDataFrame(genebody.tb)


peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
# peak.H3K27ac<- makeGRangesFromDataFrame(fread(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed")) %>% 
#                                           dplyr::mutate(chr = V1, start = (V2 + V3)/2, end = (V2 + V3)/2) %>%
#                                           dplyr::select(chr, start, end))

####### Filtering out peaks overlapping with the gene body
overlaps <- findOverlaps(genebody.gr, peak.H3K27ac)

# Indices of peaks that overlap the TSS
overlapping_peak_indices <- unique(subjectHits(overlaps))

# Exclude overlapping peaks
non_overlapping_peaks <- peak.H3K27ac[-overlapping_peak_indices]


####### Calculating distance to nearest peak
nearest_peak_indices <- nearest(genes.gr, non_overlapping_peaks)
nearest_peaks <- non_overlapping_peaks[nearest_peak_indices]
distances <- distance(genes.gr, nearest_peaks)


results <- data.frame(
  ensembl = mcols(genes.gr)$ensembl,
  gene_chr = as.character(seqnames(genes.gr)),
  gene_TSS = start(genes.gr),
  peak_chr = as.character(seqnames(nearest_peaks)),
  peak_start = start(nearest_peaks),
  peak_end = end(nearest_peaks),
  distance = distances
)

results <- results %>% dplyr::mutate(group = case_when(ensembl %in% group1 ~ "group1",
                                            ensembl %in% group2 ~ "group2",
                                            TRUE ~ NA))

ggplot(results, aes(x = group, y = distance, fill = group)) + geom_violin() + geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") + theme_bw() + ggtitle("distance to nearest H3K27ac peak excluding gene body") + scale_y_continuous(labels = label_kb_mb) + coord_cartesian(ylim = c(0, 250*1000))

  
binary group - excluding specific TSS +- 10 kb
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3), ensembl = V6, chr = V1) %>%
  dplyr::select(ensembl, chr, TSS) %>% dplyr::filter(ensembl %in% c(group1, group2))
genes.gr <- GRanges(
  seqnames = gene.tb$chr,
  ranges = IRanges(start = gene.tb$TSS, end = gene.tb$TSS),
  ensembl = gene.tb$ensembl
)

genebody.tb <- gene.tb %>% dplyr::mutate(start = TSS-10*1000, end = TSS + 10*1000) %>%
  dplyr::select(chr, start, end)
genebody.gr <- makeGRangesFromDataFrame(genebody.tb)

peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))


# Step 1: Find overlaps between gene bodies and peaks
overlaps <- findOverlaps(genebody.gr, peak.H3K27ac)

# Create a list mapping each gene to the indices of peaks overlapping with its gene body
overlapping_peaks_per_gene <- split(subjectHits(overlaps), queryHits(overlaps))

# Initialize an empty list to store results
results_list <- vector("list", length(genes.gr))

# Step 2: For each gene, exclude overlapping peaks and find the nearest peak to its TSS
for (i in seq_along(genes.gr)) {
  gene <- genes.gr[i]
  
  # Get indices of peaks overlapping with this gene's body
  overlapping_peak_indices <- overlapping_peaks_per_gene[[as.character(i)]]
  
  # Exclude overlapping peaks for this gene
  if (!is.null(overlapping_peak_indices)) {
    peaks_to_consider <- peak.H3K27ac[-overlapping_peak_indices]
  } else {
    peaks_to_consider <- peak.H3K27ac
  }
  
  # Find the nearest peak to the TSS of this gene
  nearest_peak_index <- nearest(gene, peaks_to_consider)
  
  if (is.na(nearest_peak_index)) {
    # No peaks found; set NA values
    results_list[[i]] <- data.frame(
      ensembl = mcols(gene)$ensembl,
      gene_chr = as.character(seqnames(gene)),
      gene_TSS = start(gene),
      peak_chr = NA,
      peak_start = NA,
      peak_end = NA,
      distance = NA
    )
  } else {
    nearest_peak <- peaks_to_consider[nearest_peak_index]
    dist <- distance(gene, nearest_peak)
    
    results_list[[i]] <- data.frame(
      ensembl = mcols(gene)$ensembl,
      gene_chr = as.character(seqnames(gene)),
      gene_TSS = start(gene),
      peak_chr = as.character(seqnames(nearest_peak)),
      peak_start = start(nearest_peak),
      peak_end = end(nearest_peak),
      distance = dist
    )
  }
}

# Combine results into a single data frame
results <- do.call(rbind, results_list)

# Add group information
results <- results %>% dplyr::mutate(group = case_when(
  ensembl %in% group1 ~ "group1",
  ensembl %in% group2 ~ "group2",
  TRUE ~ NA_character_
))

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group == group1) )$distance
  distance2 <- (data %>% dplyr::filter(group == group2) )$distance
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

getPvalWilcox(results, "group1", "group2")
# Plotting
ggplot(results, aes(x = group, y = distance, fill = group)) +
  geom_violin() +
  geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") +
  theme_bw() +
  ggtitle("Distance to Nearest H3K27ac Peak Excluding Gene Body Overlaps") +
  scale_y_continuous(labels = label_kb_mb) +
  coord_cartesian(ylim = c(0, 50 * 1000)) +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") 
Only limiting to E-P loops from Micro-C

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene



name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-pe_ensemblList.tsv")),
                                 diffCutoff = 0.2) %>%
  dplyr::filter(Anno2 == "P-E")

temp <- geneAnnoData %>% unnest(gene)

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3), ensembl = V6, chr = V1) %>%
  dplyr::select(ensembl, chr, TSS)

temp <- dplyr::left_join(temp, gene.tb, by = c("gene" = "ensembl"))

temp <- temp %>% dplyr::mutate(center1 = (start1 + end1)/2,
                               center2 = (start2 + end2)/2,
                               distance1 = abs(TSS-center1),
                               distance2 = abs(TSS-center2)) %>%
  dplyr::mutate(distance = pmax(distance1, distance2))

temp <- temp %>% group_by(gene) %>% summarize(min_enh_distance = min(distance)) %>%
  dplyr::mutate(group = case_when(gene %in% group1 ~ "group1",
                                  gene %in% group2 ~ "group2",
                                  TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(temp, aes(x = group, y = min_enh_distance, fill = group)) + 
  geom_violin() +
  geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") +
  theme_bw() +
  ggtitle("Distance to Nearest Enhancer fro E-P") +
  scale_y_continuous(labels = label_kb_mb)  +
  coord_cartesian(ylim = c(0, 1000 * 1000))

[2.24] (WORKING ON)Checking the percentage of non-important loops

Idea: having one non-perturbed reg loops could be enough.

name <- "chromo_cons_annoHierarchy"
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                 diffCutoff = 0.2)


loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))

geneAnnoData <- geneAnnoData %>% dplyr::filter(id %in% c(loop.up$id, loop.no$id, loop.down$id)) %>%
  dplyr::mutate(loopType = case_when(id %in% c(loop.up$id, loop.no$id) ~ "insensitive",
                                     id %in% c(loop.down$id) ~ "sensitive",
                                     TRUE ~ NA))

data <- geneAnnoData %>% dplyr::select(gene, id, loopType) %>% unnest(gene) %>%
  group_by(gene) %>% summarize(
    insensitive = sum(loopType == "insensitive", na.rm = TRUE),
    sensitive = sum(loopType == "sensitive", na.rm = TRUE))



###

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

geneGroup <- tibble(group = c(rep("group1", length(group1)), rep("group2", length(group2))),
                    gene = c(group1, group2))

data <- left_join(geneGroup, data, by = c("gene")) %>% dplyr::mutate(mutate(across(everything(), ~replace_na(., 0))))


###
data <- data %>% dplyr::mutate(presenceOfRetained = if_else(insensitive > 0, "YES", "NO"),
                       percOfRetained = if_else(insensitive + sensitive == 0, 0, 100*insensitive/(insensitive + sensitive)))


###
ggplot(data, aes(x = group, y = percOfRetained, fill = group)) + geom_violin() + 
  geom_boxplot(outlier.shape = NA, width = 0.1, fill = "white") + theme_bw()


### Stacked barplot
group <- c("group1", "group1", "group2", "group2")
presenceOfRetained <- rep(c("YES", "NO"), 2)
presenceOfRetained <- factor (presenceOfRetained, levels = c("YES", "NO"))
value <- c(nrow(data %>% dplyr::filter(group == "group1", presenceOfRetained == "YES")),
           nrow(data %>% dplyr::filter(group == "group1", presenceOfRetained == "NO")),
           nrow(data %>% dplyr::filter(group == "group2", presenceOfRetained == "YES")),
           nrow(data %>% dplyr::filter(group == "group2", presenceOfRetained == "NO")))
plotData <- data.frame(group, presenceOfRetained, value)

ggplot(plotData, aes(fill=presenceOfRetained, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()
name <- "chromo_cons_annoHierarchy"
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-pe_ensemblList.tsv")),
                                 diffCutoff = 0.2)


loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>%
  dplyr::mutate(size = V3 - V2,
                id = paste(V1, size, V2, V5, sep = "_"))

geneAnnoData <- geneAnnoData %>% dplyr::filter(id %in% c(loop.up$id, loop.no$id, loop.down$id)) %>%
  dplyr::mutate(loopType = case_when(id %in% c(loop.up$id, loop.no$id) ~ "insensitive",
                                     id %in% c(loop.down$id) ~ "sensitive",
                                     TRUE ~ NA))

data <- geneAnnoData %>% dplyr::select(gene, id, loopType) %>% unnest(gene) %>%
  group_by(gene) %>% summarize(
    insensitive = sum(loopType == "insensitive", na.rm = TRUE),
    sensitive = sum(loopType == "sensitive", na.rm = TRUE))



###

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

geneGroup <- tibble(group = c(rep("group1", length(group1)), rep("group2", length(group2))),
                    gene = c(group1, group2))

data <- left_join(geneGroup, data, by = c("gene")) %>% dplyr::mutate(mutate(across(everything(), ~replace_na(., 0))))


###
data <- data %>% dplyr::mutate(presenceOfRetained = if_else(insensitive > 0, "YES", "NO"),
                       percOfRetained = if_else(insensitive + sensitive == 0, 0, 100*insensitive/(insensitive + sensitive)))


###
ggplot(data, aes(x = group, y = percOfRetained, fill = group)) + geom_violin() + 
  geom_boxplot(outlier.shape = NA, width = 0.05, fill = "white") + theme_bw()


### Stacked barplot
group <- c("group1", "group1", "group2", "group2")
presenceOfRetained <- rep(c("YES", "NO"), 2)
presenceOfRetained <- factor (presenceOfRetained, levels = c("YES", "NO"))
value <- c(nrow(data %>% dplyr::filter(group == "group1", presenceOfRetained == "YES")),
           nrow(data %>% dplyr::filter(group == "group1", presenceOfRetained == "NO")),
           nrow(data %>% dplyr::filter(group == "group2", presenceOfRetained == "YES")),
           nrow(data %>% dplyr::filter(group == "group2", presenceOfRetained == "NO")))
plotData <- data.frame(group, presenceOfRetained, value)

ggplot(plotData, aes(fill=presenceOfRetained, y=value, x=group)) + 
    geom_bar(position="fill", stat="identity") + theme_classic()

[2.25] Obs/Exp loops

Merging obs/exp scores from different resolution & samples

G1
loops <- fread(here(consensusDir, "chromo_cons_score.tsv"))

sample <- "G1.DMSO.Merged"
for(sample in c("G1.DMSO.Merged", "G1.dTAG.Merged", "G1.A485.Merged")){
  temp.25kb <- fread(here(consensusDir, paste0("loopScore_", sample, "_25kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.25kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp.10kb <- fread(here(consensusDir, paste0("loopScore_", sample, "_10kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.10kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp.5kb <-fread(here(consensusDir, paste0("loopScore_", sample, "_5kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.5kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp <- bind_rows(temp.25kb, temp.10kb, temp.5kb)
  fwrite(temp, here(consensusDir, paste0("loopScore_", sample, ".tsv")), sep = "\t")
}


temp.DMSO <- fread(here(consensusDir, "loopScore_G1.DMSO.Merged.tsv")) %>%
  dplyr::select(id, obs, obsexp)
colnames(temp.DMSO) <- c("id", "obs_DMSO", "obsexp_DMSO")
temp.dTAG <- fread(here(consensusDir, "loopScore_G1.dTAG.Merged.tsv")) %>%
  dplyr::select(id, obs, obsexp)
colnames(temp.dTAG) <- c("id", "obs_dTAG", "obsexp_dTAG")
temp.A485 <- fread(here(consensusDir, "loopScore_G1.A485.Merged.tsv")) %>%
  dplyr::select(id, obs, obsexp)
colnames(temp.A485) <- c("id", "obs_A485", "obsexp_A485")

loops_oe <- full_join(full_join(temp.DMSO, temp.dTAG, by = "id"),
          temp.A485, by = "id") %>%
  dplyr::mutate(oeFC_dTAG_DMSO = if_else(obsexp_DMSO == 0, NA, obsexp_dTAG/obsexp_DMSO),
                oeFC_A485_DMSO = if_else(obsexp_DMSO == 0, NA, obsexp_A485/obsexp_DMSO))

fwrite(loops_oe, here(consensusDir, paste0("loopScore_cons_obsexp.tsv")), sep = "\t")
Async
loops <- fread(here(consensusDir, "chromo_cons_score.tsv"))

for(sample in c("Async.UT", "Async.AID")){
  temp.25kb <- fread(here(consensusDir, paste0("loopScore_", sample, "_25kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.25kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp.10kb <- fread(here(consensusDir, paste0("loopScore_", sample, "_10kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.10kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp.5kb <-fread(here(consensusDir, paste0("loopScore_", sample, "_5kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(chrom1, start1, end1, chrom2, start2, end2, id, observed, "O/E")
  colnames(temp.5kb) <- c("chrom1", "start1", "end1", "chrom2", "start2", "end2", "id", "obs", "obsexp")
  
  temp <- bind_rows(temp.25kb, temp.10kb, temp.5kb)
  fwrite(temp, here(consensusDir, paste0("loopScore_", sample, ".tsv")), sep = "\t")
}


temp.UT <- fread(here(consensusDir, "loopScore_Async.UT.tsv")) %>%
  dplyr::select(id, obs, obsexp)
colnames(temp.UT) <- c("id", "obs_UT", "obsexp_UT")
temp.AID <- fread(here(consensusDir, "loopScore_Async.AID.tsv")) %>%
  dplyr::select(id, obs, obsexp)
colnames(temp.AID) <- c("id", "obs_AID", "obsexp_AID")

loops_oe <- full_join(temp.UT, temp.AID, by = "id") %>%
  dplyr::mutate(oeFC_AID_UT = if_else(obsexp_UT == 0, NA, obsexp_AID/obsexp_UT))

fwrite(loops_oe, here(consensusDir, paste0("loopScore_cons_obsexp_Async.tsv")), sep = "\t")

Merging obs/exp per resolution

Only the loops that made to consensus loops are considered ##### G1

loops <- fread(here(consensusDir, "chromo_cons_score.tsv"))

res <- 25

for (res in c(25, 10, 5)){
  
  temp.DMSO <- fread(here(consensusDir, paste0("loopScore_G1.DMSO.Merged_", res, "kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(id, observed, "O/E")
  colnames(temp.DMSO) <- c("id", "obs_DMSO", "obsexp_DMSO")
  
  temp.dTAG <- fread(here(consensusDir, paste0("loopScore_G1.dTAG.Merged_", res, "kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(id, observed, "O/E")
  colnames(temp.dTAG) <- c("id", "obs_dTAG", "obsexp_dTAG")
  
  temp.A485 <- fread(here(consensusDir, paste0("loopScore_G1.A485.Merged_", res, "kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(id, observed, "O/E")
  colnames(temp.A485) <- c("id", "obs_A485", "obsexp_A485")
  
  temp <- full_join(full_join(temp.DMSO, temp.dTAG, by = c("id")), temp.A485, by = c("id")) %>% 
    dplyr::mutate(oeFC_dTAG_DMSO = if_else(obsexp_DMSO == 0, NA, obsexp_dTAG/obsexp_DMSO),
                  oeFC_A485_DMSO = if_else(obsexp_DMSO == 0, NA, obsexp_A485/obsexp_DMSO))
  
  fwrite(temp, here(consensusDir, paste0("loopScore_cons_obsexp_", res, "kb.tsv")), sep = "\t")
}
Async
loops <- fread(here(consensusDir, "chromo_cons_score.tsv"))

res <- 25

for (res in c(25, 10, 5)){
  
  temp.UT <- fread(here(consensusDir, paste0("loopScore_Async.UT_", res, "kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(id, observed, "O/E")
  colnames(temp.UT) <- c("id", "obs_UT", "obsexp_UT")
  
  temp.AID <- fread(here(consensusDir, paste0("loopScore_Async.AID_", res, "kb.tsv"))) %>%
    dplyr::mutate(binSize = end1 - start1,
                  id = paste(chrom1, binSize, start1, start2, sep = "_")) %>%
    dplyr::filter(id %in% loops$id) %>%
    dplyr::select(id, observed, "O/E")
  colnames(temp.AID) <- c("id", "obs_AID", "obsexp_AID")

  
  temp <- full_join(temp.UT, temp.AID, by = c("id")) %>% 
    dplyr::mutate(oeFC_AID_UT = if_else(obsexp_UT == 0, NA, obsexp_AID/obsexp_UT))
  
  fwrite(temp, here(consensusDir, paste0("loopScore_cons_obsexp_", res, "kb_async.tsv")), sep = "\t")
}

Comparing obs/exp from chrommosight loop scores

dTAG per res
# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

for(res in c(25, 10, 5)){
  minValue <- -4
  maxValue <- 5
  obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp_", res, "kb.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))
  
  
  # dTAG
  obsexp$density <- get_density(obsexp$log_obsexp_DMSO, obsexp$log_obsexp_dTAG, n = 100)
  obsexp <- obsexp %>% dplyr::arrange(density)
  g1 <- ggplot(obsexp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 
  
  
  # Visualize UP DOWN loops
  temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g2 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue))
  
  
  temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g3 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue))
  
  temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g4 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue))
  
  
  fileName <- paste0("obsexp_dTAG_vs_DMSO_", res, "kb")
  height <- 4
  width <- 12
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(plot_grid(g1, g4, g3, g2, ncol = 4))
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(plot_grid(g1, g4, g3, g2, ncol = 4))
  dev.off()
}
dTAG all res
# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

minValue <- -4
maxValue <- 5

obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))



# dTAG
obsexp$density <- get_density(obsexp$log_obsexp_DMSO, obsexp$log_obsexp_dTAG, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_dTAG_vs_DMSO")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_dTAG_vs_DMSO_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Plotting only subset

specificLoop.25kb <- fread(here(loopDir, "G1.DMSO.Merged_chromosight_25kb.bedpe")) %>%
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
specificLoop.10kb <- fread(here(loopDir, "G1.DMSO.Merged_chromosight_10kb.bedpe")) %>%
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
specificLoop.5kb <- fread(here(loopDir, "G1.DMSO.Merged_chromosight_5kb.bedpe")) %>%
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

specificLoops.DMSO <- c(specificLoop.25kb$id, specificLoop.10kb$id, specificLoop.5kb$id)


minValue <- -4
maxValue <- 5

obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))




# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id,
                                 id %in% specificLoops.DMSO)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id,
                                 id %in% specificLoops.DMSO)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_dTAG_vs_DMSO_str_vs_reg_DMSOspecificLoops")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Plotting 1mb
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue <- -4
maxValue <- 5
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id")) %>% dplyr::mutate(distance = start2 - start1)


# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

# distance filter
obsexp <- data %>% dplyr::filter(distance > 1e6)


# dTAG
obsexp$density <- get_density(obsexp$log_obsexp_DMSO, obsexp$log_obsexp_dTAG, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_dTAG_vs_DMSO_1mbover")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_dTAG_vs_DMSO_1mbover_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Plotting Obs
minValue <- -4
maxValue <- 10
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                  log_obs_DMSO = if_else(obs_DMSO == 0, minValue, log2(obs_DMSO)),
                  log_obs_dTAG = if_else(obs_dTAG == 0, minValue, log2(obs_dTAG)),
                  log_obs_A485 = if_else(obs_A485 == 0, minValue, log2(obs_A485)))

# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))



# dTAG
obsexp$density <- get_density(obsexp$log_obs_DMSO, obsexp$log_obs_dTAG, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_dTAG_vs_DMSO_obs")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_dTAG, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_dTAG, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_dTAG_vs_DMSO_obs_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Async.AID all res
# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

minValue <- -8
maxValue <- 7

obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp_Async.tsv"))) %>%
  dplyr::mutate(log_obsexp_UT = if_else(obsexp_UT == 0, minValue, log2(obsexp_UT)),
                log_obsexp_AID = if_else(obsexp_AID == 0, minValue, log2(obsexp_AID)))



# dTAG
obsexp$density <- get_density(obsexp$log_obsexp_UT, obsexp$log_obsexp_AID, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obsexp_UT, temp$log_obsexp_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obsexp_UT, temp$log_obsexp_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obsexp_UT, temp$log_obsexp_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_AID_vs_UT")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obsexp_UT, temp$log_obsexp_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obsexp_UT, temp$log_obsexp_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obsexp_UT, y = log_obsexp_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_AID_vs_UT_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Plotting Obs

minValue <- -20
maxValue <- 10

obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp_Async.tsv"))) %>%
  dplyr::mutate(log_obsexp_UT = if_else(obsexp_UT == 0, minValue, log2(obsexp_UT)),
                log_obsexp_AID = if_else(obsexp_AID == 0, minValue, log2(obsexp_AID)),
                log_obs_UT = if_else(obs_UT == 0, minValue, log2(obs_UT)),
                log_obs_AID = if_else(obs_AID == 0, minValue, log2(obs_AID)))

# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))



# dTAG
obsexp$density <- get_density(obsexp$log_obs_UT, obsexp$log_obs_AID, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obs_UT, temp$log_obs_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obs_UT, temp$log_obs_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obs_UT, temp$log_obs_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obs_AID_vs_UT_obs")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obs_UT, temp$log_obs_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obs_UT, temp$log_obs_AID, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obs_UT, y = log_obs_AID, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obs_AID_vs_UT_obs_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
A485 per res
# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

for(res in c(25, 10, 5)){
  minValue <- -4
  maxValue <- 5
  obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp_", res, "kb.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))
  
  
  # A485
  obsexp$density <- get_density(obsexp$log_obsexp_DMSO, obsexp$log_obsexp_A485, n = 100)
  obsexp <- obsexp %>% dplyr::arrange(density)
  g1 <- ggplot(obsexp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 
  
  
  # Visualize UP DOWN loops
  temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g2 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 
  
  
  temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g3 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 
  
  temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
  temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
  temp <- temp %>% dplyr::arrange(density)
  g4 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
    geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
    geom_abline(slope = 1, intercept = 0) +
    ggtitle(paste0(res, "kb, log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 
  
  
  fileName <- paste0("obsexp_A485_vs_DMSO_", res, "kb")
  height <- 4
  width <- 12
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(plot_grid(g1, g4, g3, g2, ncol = 4))
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(plot_grid(g1, g4, g3, g2, ncol = 4))
  dev.off()
}
A485 all res
# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))

minValue <- -4
maxValue <- 5

obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))


# A485
obsexp$density <- get_density(obsexp$log_obsexp_DMSO, obsexp$log_obsexp_A485, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_A485_vs_DMSO")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obsexp_DMSO, temp$log_obsexp_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs/exp), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_A485_vs_DMSO_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
Plotting Obs
minValue <- -4
maxValue <- 10
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                  log_obs_DMSO = if_else(obs_DMSO == 0, minValue, log2(obs_DMSO)),
                  log_obs_dTAG = if_else(obs_dTAG == 0, minValue, log2(obs_dTAG)),
                  log_obs_A485 = if_else(obs_A485 == 0, minValue, log2(obs_A485)))

# Importing loops
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_UP_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_DOWN_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_A485vsDMSO_NO_diff0.2.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))



# dTAG
obsexp$density <- get_density(obsexp$log_obs_DMSO, obsexp$log_obs_A485, n = 100)
obsexp <- obsexp %>% dplyr::arrange(density)
g1 <- ggplot(obsexp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs)")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Visualize UP DOWN loops
temp <- obsexp %>% dplyr::filter(id %in% loop.down$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g2 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), down")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


temp <- obsexp %>% dplyr::filter(id %in% loop.no$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g3 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), no")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

temp <- obsexp %>% dplyr::filter(id %in% loop.up$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g4 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), up")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 


fileName <- paste0("obsexp_A485_vs_DMSO_obs")
height <- 4
width <- 12
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g1, g4, g3, g2, ncol = 4))
dev.off()


# Structural
loop.str <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.str$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g5 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), structural loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

# Reg (PE-PE)
loop.reg <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe")) %>% 
  dplyr::mutate(binSize = V3 - V2,
                id = paste(V1, binSize, V2, V5, sep = "_"))
temp <- obsexp %>% dplyr::filter(id %in% loop.reg$id)
temp$density <- get_density(temp$log_obs_DMSO, temp$log_obs_A485, n = 100)
temp <- temp %>% dplyr::arrange(density)
g6 <- ggplot(temp, aes(x = log_obs_DMSO, y = log_obs_A485, color = density)) + 
  geom_point() + theme_bw() + scale_color_viridis(guide = "none") +
  geom_abline(slope = 1, intercept = 0) +
  ggtitle(paste0("log2(obs), regulatory loops")) +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) 

fileName <- paste0("obsexp_A485_vs_DMSO_obs_str_vs_reg")
height <- 4
width <- 6
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(g5, g6, ncol = 2))
dev.off()

[2.26] Repeating few analysis with obs/exp

Function

create_dist_vs_avgScore_perTreatment_oe <- function(data, figDir, name, loopList, colorList, se = FALSE){
  avg_scores_long <- data %>%
    group_by(distance, Anno2) %>%
    summarise(avg_score = mean(score, na.rm = TRUE)) %>%
    ungroup() 
  avg_scores_long$Anno2 <- factor(avg_scores_long$Anno2, level = loopList)
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = Anno2, fill = Anno2)) + 
    geom_smooth(show.legend = TRUE, se = se)  +
    #ylim(0, 0.5) +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = colorList) +
    scale_fill_manual(values = colorList) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Score") +
    theme(plot.title = element_text(size = 8))
  
  fileName <- paste0("dist_vs_score_linePlot_", name)
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 4, height = 3)
  print(p4)
  dev.off()
} 

create_dist_vs_avgDiffScore_perTreatment_oe <- function(data, figDir, name, loopList, colorList, se = FALSE){
  avg_scores_long <- data %>%
    group_by(distance, Anno2) %>%
    summarise(avg_score = mean(score, na.rm = TRUE)) %>%
    ungroup() 
  avg_scores_long$Anno2 <- factor(avg_scores_long$Anno2, level = loopList)
  p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = Anno2, fill = Anno2)) + 
    geom_hline(yintercept = 0) +
    geom_smooth(show.legend = TRUE, se = se)  +
    theme_classic() +  scale_x_continuous(labels = label_kb_mb) +
    scale_color_manual(values = colorList) +
    scale_fill_manual(values = colorList) +
    labs(title = paste0(name),
         x = "Distance",
         y = "Average Diff Score") +
    theme(plot.title = element_text(size = 8)) 
  
  fileName <- paste0("dist_vs_score_difflinePlot_", name)
  png(here(figDir, paste0(fileName, ".png")), 
      res = 600, units = "in", width = 4, height = 3)
  print(p4)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 4, height = 3)
  print(p4)
  dev.off()
} 

create_dist_barplot_oe <- function(data, figDir, name, note, loopList, diffCutoff, distanceFilter = 2*e6){
    data <- data %>% 
    dplyr::mutate(distance = start2 - start1,
                  updown_dTAG_DMSO = ifelse(log_obsexp_diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(log_obsexp_diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_A485_DMSO > -diffCutoff, "NO", "DOWN"))) %>%
    dplyr::filter(Anno2 %in% loopList,
                  distance < distanceFilter)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  
  temp <- data %>% dplyr::select(Anno2, distance, updown_dTAG_DMSO, updown_A485_DMSO) %>%
    dplyr::filter(Anno2 %in% loopList,
                  updown_dTAG_DMSO %in% c("UP", "NO", "DOWN"))
  p <- ggplot(temp, aes(x = updown_dTAG_DMSO, y = distance)) +
    geom_violin(aes(fill = updown_dTAG_DMSO)) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = updown_dTAG_DMSO), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + ggtitle(note) +
    scale_y_continuous(labels = label_kb_mb)
  fileName <- paste0("size_barplot_", name, "_dTAG_vs_DMSO_", note, "_", diffCutoff)
  height <- 3
  width <- 4
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
  
  
  temp <- data %>% dplyr::select(Anno2, distance, updown_dTAG_DMSO, updown_A485_DMSO) %>%
    dplyr::filter(Anno2 %in% loopList,
                  updown_A485_DMSO %in% c("UP", "NO",  "DOWN"))
  p <- ggplot(temp, aes(x = updown_A485_DMSO, y = distance)) +
    geom_violin(aes(fill = updown_A485_DMSO)) + 
    geom_boxplot(width = 0.1, outlier.shape = NA) +
    stat_summary(aes(group = updown_A485_DMSO), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
    theme_classic() + ggtitle(note) +
    scale_y_continuous(labels = label_kb_mb)
  fileName <- paste0("size_barplot_", name, "_A485_vs_DMSO_", note, "_", diffCutoff)
  height <- 3
  width <- 4
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

create_loop_scatterplot_oe <- function(data, figDir, name, Anno2List, diffCutoff){
  data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(log_obsexp_diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(log_obsexp_diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_A485_DMSO > -diffCutoff, "NO", "DOWN"))) %>%
    dplyr::filter(Anno2 %in% Anno2List)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  num.up <- (summary(data$updown_dTAG_DMSO))["UP"]
  num.no <- (summary(data$updown_dTAG_DMSO))["NO"]
  num.down <- (summary(data$updown_dTAG_DMSO))["DOWN"]
  num.all <- num.up + num.no + num.down
  perc.up <- round(num.up / num.all * 100, 2)
  perc.no <- round(num.no / num.all * 100, 2)
  perc.down <- round(num.down / num.all * 100, 2)
  
  ### Scatterplot
    minValue <- -4
  maxValue <- 5
  data$density <- get_density(data$log_obsexp_DMSO, data$log_obsexp_dTAG, n = 100)
  data <- data %>% dplyr::arrange(density)
  correlation <- cor(data$log_obsexp_DMSO, data$log_obsexp_dTAG)
  p1 <- ggplot(data, aes(x = log_obsexp_DMSO, y = log_obsexp_dTAG, color = density)) +
    geom_point(show.legend = FALSE) + 
    scale_color_viridis() +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) +
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
    annotate("text", x = minValue, y = maxValue, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
             color = "black", hjust = 0, size = 3) +
    annotate("text", x = minValue, y = maxValue-1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
             color = "black", hjust = 0, size = 3) +
    annotate("text", x = minValue, y = maxValue-2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
             color = "black", hjust = 0, size = 3) +
    theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5)) +
    annotate("text", x = minValue, y = maxValue, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

  
  
  num.up <- (summary(data$updown_A485_DMSO))["UP"]
  num.no <- (summary(data$updown_A485_DMSO))["NO"]
  num.down <- (summary(data$updown_A485_DMSO))["DOWN"]
  num.all <- num.up + num.no + num.down
  perc.up <- round(num.up / num.all * 100, 2)
  perc.no <- round(num.no / num.all * 100, 2)
  perc.down <- round(num.down / num.all * 100, 2)
  
  data$density <- get_density(data$log_obsexp_DMSO, data$log_obsexp_A485, n = 100)
  data <- data %>% dplyr::arrange(density)
  correlation <- cor(data$log_obsexp_DMSO, data$log_obsexp_A485)
  p2 <- ggplot(data, aes(x = log_obsexp_DMSO, y = log_obsexp_A485, color = density)) +
    geom_point(show.legend = FALSE) + 
    scale_color_viridis() +
    coord_fixed(xlim = c(minValue, maxValue), ylim = c(minValue, maxValue)) +
    geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
    geom_abline(slope = 1, intercept = -diffCutoff, col = "grey", linetype = "dotted") +
    geom_abline(slope = 1, intercept = diffCutoff, col = "grey", linetype = "dotted") +
    geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
    geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
    annotate("text", x = minValue, y = maxValue, label = paste0("UP: ", num.up, " (", perc.up, "%)"), 
             color = "black", hjust = 0, size = 3) +
    annotate("text", x = minValue, y = maxValue-1, label = paste0("NO: ", num.no, " (", perc.no, "%)"), 
             color = "black", hjust = 0, size = 3) +
    annotate("text", x = minValue, y = maxValue-2, label = paste0("DOWN: ", num.down, " (", perc.down, "%)"), 
             color = "black", hjust = 0, size = 3) +
    theme_classic() + ggtitle(name) + theme(plot.title = element_text(size = 5)) +
    annotate("text", x = minValue, y = maxValue, label = paste("r =", round(correlation, 2)), size = 5, color = "black")

  
  
  fileName <- paste0("scatterplot_", name, "_", diffCutoff)
  png(here(figDir, paste0(fileName, ".png")), res = 600, units = "in", width = 5*1.5, height = 2.5*1.5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
  
  svglite(here(figDir, paste0(fileName, ".svg")), 
          width = 5*1.5, height = 2.5*1.5)
  print(cowplot::plot_grid(p1, p2, align = "h"))
  dev.off()
}

make_diff_bedpe_oe <- function(data, name, Anno2List, outDir, diffCutoff){
  data <- data %>%
    dplyr::mutate(updown_dTAG_DMSO = ifelse(log_obsexp_diff_dTAG_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_dTAG_DMSO > -diffCutoff, "NO", "DOWN")),
                  updown_A485_DMSO = ifelse(log_obsexp_diff_A485_DMSO > diffCutoff, "UP", 
                                            ifelse(log_obsexp_diff_A485_DMSO > -diffCutoff, "NO", "DOWN"))) %>%
    dplyr::filter(Anno2 %in% Anno2List)
  data$updown_dTAG_DMSO <- factor(data$updown_dTAG_DMSO, levels = c("UP", "NO", "DOWN"))
  data$updown_A485_DMSO <- factor(data$updown_A485_DMSO, levels = c("UP", "NO", "DOWN"))
  
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "UP") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_UP_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "NO") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_NO_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_dTAG_DMSO == "DOWN") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_dTAGvsDMSO_DOWN_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "UP") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_UP_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "NO") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_NO_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
  out.temp <- data %>% dplyr::filter(updown_A485_DMSO == "DOWN") %>% dplyr::select(c(1, 2, 3, 4, 5, 6))
  fwrite(out.temp, here(outDir, paste0(name, "_A485vsDMSO_DOWN_diff", diffCutoff, ".bedpe")), 
         sep = "\t", col.names = FALSE)
}

Distance vs score plot

dTAG
OE
# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id"))

# Plot
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, log_obsexp_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment_oe(temp, figDir, paste0(name, "_DMSO_logOE"), unique(data$Anno2), colorListLoop)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, log_obsexp_dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment_oe(temp, figDir, paste0(name, "_dTAG_logOE"), unique(data$Anno2), colorListLoop)


# Creating figures per each condition, differential
temp <- data %>% dplyr::mutate(distance = start2 - start1,
                               log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO) %>% 
  dplyr::select(distance, log_obsexp_diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment_oe(temp, figDir, paste0(name, "_dTAG_logOE"), unique(data$Anno2), colorListLoop)
OE, grouped
# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id"))

temp <- data %>% dplyr::mutate(distance = start2 - start1,
                               log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO) %>% 
  dplyr::select(distance, log_obsexp_diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")



temp <- temp %>% dplyr::mutate(Anno3 = case_when(Anno2 %in% c("S-X", "S-S") ~ "Structural",
                                                 Anno2 %in% c("P-P", "P-E", "E-E") ~ "Pure_Regulatory",
                                                 Anno2 %in% c("P-S", "P-X", "E-S", "E-X") ~ "Relaxed_Regulatory")) %>%
  dplyr::filter(!is.na(Anno3))

loopList <- rev(c("Structural", "Relaxed_Regulatory", "Pure_Regulatory"))
colorList <- rev(c(palette_3[["grey2"]], strong_green, darken(strong_green, amount = 0.5)))
avg_scores_long <- temp %>%
  group_by(distance, Anno3) %>%
  summarise(avg_score = mean(score, na.rm = TRUE)) %>%
  ungroup() 
avg_scores_long$Anno3 <- factor(avg_scores_long$Anno3, level = loopList)

p4 <- ggplot(avg_scores_long, aes(x = distance, y = avg_score, color = Anno3)) + 
  geom_hline(yintercept = 0,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") +
  geom_smooth(show.legend = TRUE, se = TRUE,
              size = lineThick*mmToLineUnit,
              lineend = "square",
              aes(fill = Anno3))  +
  theme_classic() + 
  scale_x_continuous(labels = label_kb_mb) +
  scale_color_manual(values = colorList) +
  scale_fill_manual(values = colorList) +
  labs(x = "Loop size",
       y = "Δ log2(obs/exp)",
       color = "Loop types", fill = "Loop types") +
  theme(
    axis.title = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +
  guides(
    color = guide_legend(
      keywidth = 0.5,  # Adjust the width of the legend color squares
      keyheight = 0.5  # Adjust the height of the legend color squares
    )
  )





fileName <- paste0("dist_vs_score_difflinePlot_grouped", name)

width <- panelSize(2.5)*mmToInch
height <- panelSize(1.25)*mmToInch
png(here(figDir, paste0(fileName, ".png")), 
    res = 600, units = "in", width = width, height = height)
print(p4)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")), 
        width = width, height = height)
print(p4)
dev.off()
Observed
# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obs_DMSO = if_else(obs_DMSO == 0, minValue, log2(obs_DMSO)),
                  log_obs_dTAG = if_else(obs_dTAG == 0, minValue, log2(obs_dTAG)),
                  log_obs_A485 = if_else(obs_A485 == 0, minValue, log2(obs_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id"))

# Plot
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, log_obs_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment_oe(temp, figDir, paste0(name, "_DMSO_logObs"), unique(data$Anno2), colorListLoop)

temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, log_obs_dTAG, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment_oe(temp, figDir, paste0(name, "_dTAG_logObs"), unique(data$Anno2), colorListLoop)


# Creating figures per each condition, differential
temp <- data %>% dplyr::mutate(distance = start2 - start1,
                               log_obs_diff_dTAG_DMSO = log_obs_dTAG - log_obs_DMSO) %>% 
  dplyr::select(distance, log_obs_diff_dTAG_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment_oe(temp, figDir, paste0(name, "_dTAG_logObs"), unique(data$Anno2), colorListLoop)
A485
# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id"))

# Plot
temp <- data %>% dplyr::mutate(distance = start2 - start1) %>% dplyr::select(distance, log_obsexp_A485, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgScore_perTreatment_oe(temp, figDir, paste0(name, "_A485_logOE"), unique(data$Anno2), colorListLoop)


# Creating figures per each condition, differential
temp <- data %>% dplyr::mutate(distance = start2 - start1,
                               log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO) %>% 
  dplyr::select(distance, log_obsexp_diff_A485_DMSO, Anno2)
colnames(temp) <- c("distance", "score", "Anno2")
create_dist_vs_avgDiffScore_perTreatment_oe(temp, figDir, paste0(name, "_A485_logOE"), unique(data$Anno2), colorListLoop)

Get size distribution of differential loops

# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue = -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id")) %>%
  dplyr::mutate(log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

diffCutoff <- 0.5
create_loop_scatterplot_oe(data, figDir, paste0(name, "_logOE_", "all"), unique(data$Anno2), diffCutoff)
create_loop_scatterplot_oe(data, figDir, paste0(name, "_logOE_", "reg"), c("P-P", "P-E", "E-E"), diffCutoff)
create_loop_scatterplot_oe(data, figDir, paste0(name, "_logOE_", "str"), c("S-S", "S-X"), diffCutoff)



create_dist_barplot_oe(data, figDir, paste0(name, "_logOE"), "all",  unique(data$Anno2), diffCutoff)
create_dist_barplot_oe(data, figDir, paste0(name, "_logOE"), "reg",  c("P-P", "P-E", "E-E"), diffCutoff)
create_dist_barplot_oe(data, figDir, paste0(name, "_logOE"), "reg_1mb",  c("P-P", "P-E", "E-E"), diffCutoff, 1e6)
create_dist_barplot_oe(data, figDir, paste0(name, "_logOE"), "str",  c("S-S", "S-X"), diffCutoff)
create_dist_barplot_oe(data, figDir, paste0(name, "_logOE"), "str_1mb",  c("S-S", "S-X"), diffCutoff, 1e6)

Splitting loops into diff bedpe

# Import annotation
name <- "chromo_cons_annoHierarchy"
data <- fread(here(consensusDir, paste0(name, ".tsv")))

# Import obs/exp scores and merge to the dataset
minValue = -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
    dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                  log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                  log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)))

# Merge dataset
data <- data %>% dplyr::left_join(obsexp, by = c("id")) %>%
  dplyr::mutate(log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)
diffCutoff <- 0.5
make_diff_bedpe_oe(data, paste0(name, "_logOE_", "all"), unique(data$Anno2), consensusDir, diffCutoff)
make_diff_bedpe_oe(data, paste0(name, "_logOE_", "pe-pe"), c("P-P", "P-E", "E-E"), consensusDir, diffCutoff)
make_diff_bedpe_oe(data, paste0(name, "_logOE_", "str"), c("S-S", "S-X"), consensusDir, diffCutoff)

[2.27] Extracting TSS for deeptools

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

flankSize <- 1
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl")

bed.1 <- gene.tb %>% dplyr::filter(ensembl %in% group1) %>% dplyr::select(c(1, 2, 3))
bed.2 <- gene.tb %>% dplyr::filter(ensembl %in% group2) %>% dplyr::select(c(1, 2, 3))

fwrite(bed.1, here(refDir, "TSS_binaryGroup1.bed"), sep = "\t", col.names = FALSE)
fwrite(bed.2, here(refDir, "TSS_binaryGroup2.bed"), sep = "\t", col.names = FALSE)



gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed"))

bed.1 <- gene.tb %>% dplyr::filter(V6 %in% group1)
bed.2 <- gene.tb %>% dplyr::filter(V6 %in% group2)

fwrite(bed.1, here(refDir, "TSS_binaryGroup1_gtf.bed"), sep = "\t", col.names = FALSE)
fwrite(bed.2, here(refDir, "TSS_binaryGroup2_gtf.bed"), sep = "\t", col.names = FALSE)

[2.28] Checking gene expression levels of binaryGroup

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

data <- fread(here(refDir, "readCount.filtered.TPM.all.tsv")) %>% dplyr::mutate(
  group = case_when(ensembl %in% group1 ~ "group1",
                    ensembl %in% group2 ~ "group2",
                    TRUE ~ NA)
) %>%
  dplyr::filter(!is.na(group)) %>%
  dplyr::select(c(34, 1, 3, 4, 5, 14, 15, 34))

data <- data %>% mutate(average = rowMeans(across(colnames(data)[3:7])))

temp <- data %>% dplyr::select(group, average)


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$average
  distance2 <- (data %>% dplyr::filter(group ==group2) )$average
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pval <- convPvalue(getPvalWilcox(temp, "group1", "group2"))

ggplot(temp, aes(x = group, y = average)) + geom_boxplot() + scale_y_log10() +
  ylab("avgTPM") + theme_classic() +
  annotate("text", x = 1, y = 10000, label = pval)

[2.29] Checking overlap with Stripes

group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

flankSize <- 1
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl")

bed.1 <- gene.tb %>% dplyr::filter(ensembl %in% group1) %>% dplyr::select(c(1, 2, 3))
bed.2 <- gene.tb %>% dplyr::filter(ensembl %in% group2) %>% dplyr::select(c(1, 2, 3))


data <- fread(here("../..", "result", "stripenn", "result_filtered.tsv"))

ggplot(data, aes(x = width)) + geom_histogram() + theme_classic() +
 scale_x_continuous(labels = label_kb_mb)


## Checking overlap with gene TSS

tss <- fread(here(refDir, "mm10_GRCm38.p6_TSS2.5kb.bed"))

tss.group1 <- tss %>% dplyr::filter(V6 %in% group1) %>% dplyr::select(V1, V2, V3)
colnames(tss.group1) <- c("chr", "start", "end")
tss.group1.gr <- makeGRangesFromDataFrame(tss.group1)

tss.group2 <- tss %>% dplyr::filter(V6 %in% group2) %>% dplyr::select(V1, V2, V3)
colnames(tss.group2) <- c("chr", "start", "end")
tss.group2.gr <- makeGRangesFromDataFrame(tss.group2)

## Anchor of stripes
temp <- data %>% dplyr::select(chr, pos1, pos2)
colnames(temp) <- c("chr", "start", "end")

stripeAnchor.gr <- makeGRangesFromDataFrame(temp)

overlap.group1 <- findOverlaps(tss.group1.gr, stripeAnchor.gr)
overlap.group2 <- findOverlaps(tss.group2.gr, stripeAnchor.gr)

length(unique(queryHits(overlap.group1)))
length(unique(queryHits(overlap.group2)))


## body of stripes
temp <- data %>% dplyr::select(chr, pos3, pos4)
colnames(temp) <- c("chr", "start", "end")

stripeBody.gr <- makeGRangesFromDataFrame(temp)

overlap.group1 <- findOverlaps(tss.group1.gr, stripeBody.gr)
overlap.group2 <- findOverlaps(tss.group2.gr, stripeBody.gr)

length(unique(queryHits(overlap.group1)))
length(unique(queryHits(overlap.group2)))

## Checking RAD21/CTCF presence at anchor
overlap.body.ctcf <- findOverlaps(stripeBody.gr, peak.CTCF)
overlap.body.rad21 <- findOverlaps(stripeBody.gr, peak.RAD21)
overlap.anchor.ctcf <- findOverlaps(stripeAnchor.gr, peak.CTCF)
overlap.anchor.rad21 <- findOverlaps(stripeAnchor.gr, peak.RAD21)

length(unique(queryHits(overlap.body.ctcf)))
length(unique(queryHits(overlap.body.rad21)))

length(unique(queryHits(overlap.anchor.ctcf)))
length(unique(queryHits(overlap.anchor.rad21)))
  
## Checking overlap with loop anchor (PE-PE)
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)


overlap.body.upno <- findOverlaps(stripeBody.gr, anchor.upno)
overlap.body.down <- findOverlaps(stripeBody.gr, anchor.down)
overlap.anchor.upno <- findOverlaps(stripeAnchor.gr, anchor.upno)
overlap.anchor.down <- findOverlaps(stripeAnchor.gr, anchor.down)

length(unique(subjectHits(overlap.body.upno)))
length(unique(subjectHits(overlap.body.down)))
length(unique(subjectHits(overlap.anchor.upno)))
length(unique(subjectHits(overlap.anchor.down)))


## Checking overlap with loop anchor (ALL)
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)


overlap.body.upno <- findOverlaps(stripeBody.gr, anchor.upno)
overlap.body.down <- findOverlaps(stripeBody.gr, anchor.down)
overlap.anchor.upno <- findOverlaps(stripeAnchor.gr, anchor.upno)
overlap.anchor.down <- findOverlaps(stripeAnchor.gr, anchor.down)

length(unique(subjectHits(overlap.body.upno)))
length(unique(subjectHits(overlap.body.down)))
length(unique(subjectHits(overlap.anchor.upno)))
length(unique(subjectHits(overlap.anchor.down)))


## Checking overlap with loop anchor (Structure)
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)

overlap.body.upno <- findOverlaps(stripeBody.gr, anchor.upno)
overlap.body.down <- findOverlaps(stripeBody.gr, anchor.down)
overlap.anchor.upno <- findOverlaps(stripeAnchor.gr, anchor.upno)
overlap.anchor.down <- findOverlaps(stripeAnchor.gr, anchor.down)

length(unique(subjectHits(overlap.body.upno)))
length(unique(subjectHits(overlap.body.down)))
length(unique(subjectHits(overlap.anchor.upno)))
length(unique(subjectHits(overlap.anchor.down)))


length(unique(subjectHits(overlap.body.upno)))/length(anchor.upno)*100
length(unique(subjectHits(overlap.body.down)))/length(anchor.down)*100
length(unique(subjectHits(overlap.anchor.upno)))/length(anchor.upno)*100
length(unique(subjectHits(overlap.anchor.down)))/length(anchor.down)*100


## Checking overlap with loop anchor (RelaxedReg)
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_regulatory_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_regulatory_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_regulatory_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)

overlap.body.upno <- findOverlaps(stripeBody.gr, anchor.upno)
overlap.body.down <- findOverlaps(stripeBody.gr, anchor.down)
overlap.anchor.upno <- findOverlaps(stripeAnchor.gr, anchor.upno)
overlap.anchor.down <- findOverlaps(stripeAnchor.gr, anchor.down)

length(unique(subjectHits(overlap.body.upno)))
length(unique(subjectHits(overlap.body.down)))
length(unique(subjectHits(overlap.anchor.upno)))
length(unique(subjectHits(overlap.anchor.down)))


length(unique(subjectHits(overlap.body.upno)))/length(anchor.upno)*100
length(unique(subjectHits(overlap.body.down)))/length(anchor.down)*100
length(unique(subjectHits(overlap.anchor.upno)))/length(anchor.upno)*100
length(unique(subjectHits(overlap.anchor.down)))/length(anchor.down)*100

[2.30] Hubs from Dylan Paper

All loops

results <- tibble(i = numeric(), upno = numeric(), down = numeric())

for(i in seq(1, 10)){
  data <- fread(here(refDir, "Dylan_hub_esc.csv"))
  
  data.hub <- data %>% dplyr::filter(all_lcon > i)
  temp <- data.hub %>% dplyr::select(c(1, 2, 3))
  colnames(temp) <- c("chr", "start", "end")
  hub.anchor <- makeGRangesFromDataFrame(temp)
  
  
  
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_all_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)

  
  overlap.upno <- findOverlaps(anchor.upno, hub.anchor)
  overlap.down <- findOverlaps(anchor.down, hub.anchor)
  
  n1 <- length(unique(queryHits(overlap.upno)))
  n2 <- length(unique(queryHits(overlap.down)))
  
  perc1 <- round(n1/length(overlap.upno)*100, 2)
  perc2 <- round(n2/length(overlap.down)*100, 2)
  
  results <- results %>% add_row(i = i, upno = perc1, down = perc2)
}



results_long <- results %>%
  pivot_longer(cols = c(upno, down), names_to = "Group", values_to = "Percentage")

results_long$Group <- factor(results_long$Group, levels = c("upno", "down"))
# Create the bar plot
ggplot(results_long, aes(x = factor(i), y = Percentage, fill = Group)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "All loops",
    x = "Presence of hub anchor with >i connections",
    y = "Percentage"
  ) +
  theme_minimal() +
  scale_fill_manual(values = c("upno" = "blue", "down" = "red")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + ylim(0, 100)
Fishers
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
loop.upno <- (bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))

getOverlapLoopNum <- function(loop, peak){
  anchor1 <- GRanges(seqnames = loop$V1, ranges = IRanges(start = loop$V2, end = loop$V3))
  anchor2 <- GRanges(seqnames = loop$V4, ranges = IRanges(start = loop$V5, end = loop$V6))
  a <- queryHits(findOverlaps(anchor1, peak))
  b <- queryHits(findOverlaps(anchor2, peak))
  return(length(unique(c(a, b))))
}

getSEOverlapFisher <- function(allLoop, subsetLoop, peak){
  all.overlap <- getOverlapLoopNum(allLoop, peak)
  all.notOverlap <- nrow(allLoop) - all.overlap
  
  subset.overlap <- getOverlapLoopNum(subsetLoop, peak)
  subset.notOverlap <- nrow(subsetLoop) - subset.overlap
  
  contingency_table <- matrix(c(subset.overlap, subset.notOverlap,
                                all.overlap, all.notOverlap), nrow = 2, byrow = TRUE)
  colnames(contingency_table) <- c("Overlapping", "Not_Overlapping")
  rownames(contingency_table) <- c("All loops", "Subset loops")
  
  # Perform Fisher's Exact Test
  fisher_test_result <- fisher.test(contingency_table)
  return(fisher_test_result)
}

name <- "chromo_cons_annoHierarchy"
loop <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe.bedpe"))


i <- 2
data <- fread(here(refDir, "Dylan_hub_esc.csv"))

data.hub <- data %>% dplyr::filter(all_lcon > i)
temp <- data.hub %>% dplyr::select(c(1, 2, 3))
colnames(temp) <- c("chr", "start", "end")
hub.anchor <- makeGRangesFromDataFrame(temp)


temp <- getSEOverlapFisher(loop, loop.upno, hub.anchor)
result.tb <- tibble(loopType = "UP/NO",
                    target = paste0("hub_", i),
                    pvalue = temp$p.value,
                    oddsRatio = temp$estimate)
temp <- getSEOverlapFisher(loop, loop.down, hub.anchor)
result.tb <- result.tb %>% 
  add_row(loopType = "DOWN",
          target =  paste0("hub_", i),
          pvalue = temp$p.value,
          oddsRatio = temp$estimate)


for(i in c(5)){
  data <- fread(here(refDir, "Dylan_hub_esc.csv"))
  
  data.hub <- data %>% dplyr::filter(all_lcon > i)
  temp <- data.hub %>% dplyr::select(c(1, 2, 3))
  colnames(temp) <- c("chr", "start", "end")
  hub.anchor <- makeGRangesFromDataFrame(temp)
  
  
  temp <- getSEOverlapFisher(loop, loop.upno, hub.anchor)
  result.tb <- result.tb %>% add_row(loopType = "UP/NO",
                      target = paste0("hub_", i),
                      pvalue = temp$p.value,
                      oddsRatio = temp$estimate)
  temp <- getSEOverlapFisher(loop, loop.down, hub.anchor)
  result.tb <- result.tb %>% 
    add_row(loopType = "DOWN",
            target =  paste0("hub_", i),
            pvalue = temp$p.value,
            oddsRatio = temp$estimate)
  
  
}

library(circlize)
data <- result.tb
heatmap_data <- data %>% dplyr::select(target, loopType, oddsRatio) %>%
pivot_wider(names_from = loopType, values_from = oddsRatio) %>%
  column_to_rownames(var = "target")

pvalue_data <- data %>% dplyr::select(target, loopType, pvalue) %>%
  pivot_wider(names_from = loopType, values_from = pvalue) %>%
  column_to_rownames(var = "target")

# col_fun <- colorRamp2(c(0, 1, 2), 
#                       c("blue", "white", "red"))

data$target <- factor(data$target, levels = c("hub_5", "hub_2"))
data$loopType <- factor(data$loopType, levels = c("UP/NO", "DOWN"))
p <- ggplot(data, aes(x = loopType, y = target, size = -log10(pvalue), fill = oddsRatio)) +
  geom_point(shape = 21,        # Ensures a point with an outline
             stroke = 1*ptToMM      # Line width for the border
  ) + theme_bw() + 
  scale_size_continuous(range = c(1, 3)) +  # Set min and max point sizes here
  scale_fill_gradientn(colors = c("#4852A0", "white", "#CB333A"),  # Define gradient colors
                      values = scales::rescale(c(0.5, 1, 1.5)), limits = c(0.5, 1.5), 
                      #low = "white", high = "#CB333A",
                      #                  limits = c(1, 3),
                      oob = scales::squish, # Define gradient colors
                      guide = guide_colorbar(
                        barwidth = 1.5/5.08,  # Adjust width of the color bar
                        barheight = 15/5.08   # Adjust height of the color bar
                      )
  ) + labs(x = NULL, y = NULL)  +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )


fileName <- here(figDir, "heatmap_hub_enrichment_dotplot_all")
width <- panelSize(1.65)*mmToInch
height <- panelSize(1.1)*mmToInch
# # png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
# # print(p)
# # dev.off()
svglite(paste0(fileName, ".svg"),  height = height, width = width)
print(p)
dev.off()

PE-PE loops

results <- tibble(i = numeric(), upno = numeric(), down = numeric())

for(i in seq(1, 10)){
  data <- fread(here(refDir, "Dylan_hub_esc.csv"))
  
  data.hub <- data %>% dplyr::filter(all_lcon > i)
  temp <- data.hub %>% dplyr::select(c(1, 2, 3))
  colnames(temp) <- c("chr", "start", "end")
  hub.anchor <- makeGRangesFromDataFrame(temp)
  
  
  
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)


  
  overlap.upno <- findOverlaps(anchor.upno, hub.anchor)
  overlap.down <- findOverlaps(anchor.down, hub.anchor)
  
  n1 <- length(unique(queryHits(overlap.upno)))
  n2 <- length(unique(queryHits(overlap.down)))
  
  perc1 <- round(n1/length(overlap.upno)*100, 2)
  perc2 <- round(n2/length(overlap.down)*100, 2)
  
  results <- results %>% add_row(i = i, upno = perc1, down = perc2)
}



results_long <- results %>%
  pivot_longer(cols = c(upno, down), names_to = "Group", values_to = "Percentage")
results_long$Group <- factor(results_long$Group, levels = c("upno", "down"))

# Create the bar plot
ggplot(results_long, aes(x = factor(i), y = Percentage, fill = Group)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "PE-PE loops",
    x = "Presence of hub anchor with >i connections",
    y = "Percentage"
  ) +
  theme_minimal() +
  scale_fill_manual(values = c("upno" = "blue", "down" = "red")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + ylim(0, 100)

Str loops

results <- tibble(i = numeric(), upno = numeric(), down = numeric())

for(i in seq(1, 10)){
  data <- fread(here(refDir, "Dylan_hub_esc.csv"))
  
  data.hub <- data %>% dplyr::filter(all_lcon > i)
  temp <- data.hub %>% dplyr::select(c(1, 2, 3))
  colnames(temp) <- c("chr", "start", "end")
  hub.anchor <- makeGRangesFromDataFrame(temp)
  
  
  
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_UP_diff0.2.bedpe"))
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_NO_diff0.2.bedpe"))
anchor.upno <- extractAnchor(bind_rows(loop.up, loop.no))

loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_structure_dTAGvsDMSO_DOWN_diff0.2.bedpe"))
anchor.down <- extractAnchor(loop.down)

  
  overlap.upno <- findOverlaps(anchor.upno, hub.anchor)
  overlap.down <- findOverlaps(anchor.down, hub.anchor)
  
  n1 <- length(unique(queryHits(overlap.upno)))
  n2 <- length(unique(queryHits(overlap.down)))
  
  perc1 <- round(n1/length(overlap.upno)*100, 2)
  perc2 <- round(n2/length(overlap.down)*100, 2)
  
  results <- results %>% add_row(i = i, upno = perc1, down = perc2)
}



results_long <- results %>%
  pivot_longer(cols = c(upno, down), names_to = "Group", values_to = "Percentage")
results_long$Group <- factor(results_long$Group, levels = c("upno", "down"))

# Create the bar plot
ggplot(results_long, aes(x = factor(i), y = Percentage, fill = Group)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "Structure loops",
    x = "Presence of hub anchor with >i connections",
    y = "Percentage"
  ) +
  theme_minimal() +
  scale_fill_manual(values = c("upno" = "blue", "down" = "red")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + ylim(0, 100)

TSS

results <- tibble(i = numeric(), perc1 = numeric(), perc2 = numeric())

for(i in seq(1, 10)){
  data <- fread(here(refDir, "Dylan_hub_episc.csv"))
  
  data.hub <- data %>% dplyr::filter(all_lcon > i)
  temp <- data.hub %>% dplyr::select(c(1, 2, 3))
  colnames(temp) <- c("chr", "start", "end")
  hub.anchor <- makeGRangesFromDataFrame(temp)
  
  
  
  ## Checking overlap with gene TSS
  tss <- fread(here(refDir, "mm10_GRCm38.p6_TSS2.5kb.bed"))
  
  tss.group1 <- tss %>% dplyr::filter(V6 %in% group1) %>% dplyr::select(V1, V2, V3)
  colnames(tss.group1) <- c("chr", "start", "end")
  tss.group1.gr <- makeGRangesFromDataFrame(tss.group1)
  
  tss.group2 <- tss %>% dplyr::filter(V6 %in% group2) %>% dplyr::select(V1, V2, V3)
  colnames(tss.group2) <- c("chr", "start", "end")
  tss.group2.gr <- makeGRangesFromDataFrame(tss.group2)
  
  
  overlap.group1 <- findOverlaps(tss.group1.gr, hub.anchor)
  overlap.group2 <- findOverlaps(tss.group2.gr, hub.anchor)
  
  n1 <- length(unique(queryHits(overlap.group1)))
  n2 <- length(unique(queryHits(overlap.group2)))
  
  perc1 <- round(n1/nrow(tss.group1)*100, 2)
  perc2 <- round(n2/nrow(tss.group2)*100, 2)
  
  results <- results %>% add_row(i = i, perc1 = perc1, perc2 = perc2)
}



results_long <- results %>%
  pivot_longer(cols = c(perc1, perc2), names_to = "Group", values_to = "Percentage")

# Create the bar plot
ggplot(results_long, aes(x = factor(i), y = Percentage, fill = Group)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "Percentage by 'i' for perc1 and perc2",
    x = "Presence of hub anchor with >i connections",
    y = "Percentage"
  ) +
  theme_minimal() +
  scale_fill_manual(values = c("perc1" = "blue", "perc2" = "red")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

###[2.30] H3K27ac peak number per 10kb

process_group <- function(group_name, gene_data, bins) {
  # Filter for the specific group
  TSS_group <- makeGRangesFromDataFrame(
    gene_data %>% filter(ensembl %in% get(group_name)), 
    keep.extra.columns = TRUE
  )
  
  # Process each TSS in the group
  all_results <- map_dfr(seq_len(length(TSS_group)), function(i) {
    # Find overlapping bins
    overlapping_bins <- findOverlaps(TSS_group[i], bins)
    bins_near_tss <- as_tibble(bins[subjectHits(overlapping_bins)])
    
    # Calculate distance bin
    TSScenter <- (as_tibble(TSS_group[i]) %>%
                    mutate(center = (start + end) / 2))$center
    centerBinStart <- floor(TSScenter / 10e3) * 10e3 + 1
    bins_near_tss <- bins_near_tss %>%
      mutate(distanceBin = abs((start - centerBinStart)) / 10e3)
    
    # Summarize results
    result <- bins_near_tss %>%
      group_by(distanceBin) %>%
      summarise(mean_peak_counts = mean(peak_counts, na.rm = TRUE), .groups = "drop") %>%
      mutate(gene = TSS_group[i]$ensembl)
    return(result)
  })
  
  # Calculate mean and SD for the group
  mean_data <- all_results %>%
    group_by(distanceBin) %>%
    summarise(mean_peak_counts = mean(mean_peak_counts, na.rm = TRUE))
  
  sd_data <- all_results %>%
    group_by(distanceBin) %>%
    summarise(sd_peak_counts = sd(mean_peak_counts, na.rm = TRUE))
  
  # Join and add group name
  summary_data <- left_join(mean_data, sd_data, by = "distanceBin") %>%
    mutate(group = group_name)
  
  return(summary_data)
}

##########################################################



## Import peak
refDir <- here("../..", "reference")
#peak.H3K27ac <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
peak.H3K27ac <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
#peak.H3K27ac <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))

## Import 10kb bin
temp <- fread(here(refDir, "mm10.bin.10kb.bed"))
colnames(temp) <- c("chr", "start", "end")
temp <- temp %>% dplyr::mutate(start = start+1)
bins.10kb <- makeGRangesFromDataFrame(temp)

## Count overlap
counts <- countOverlaps(bins.10kb, peak.H3K27ac)
mcols(bins.10kb)$peak_counts <- counts

## Getting TSS
flankSize <- 1e6
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl")

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

#TSS1mb.group1.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group1), keep.extra.columns = TRUE)
#TSS1mb.group2.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group2), keep.extra.columns = TRUE)

##########################################################
# List of groups to process
groups <- c("gene.group1", "gene.group2")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group1") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group2")

# Plot the results
p <- ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 0.5) +
  labs(
    x = "Distance bin (10kb)",
    y = "H3K4me3 peak count"
  ) +
  theme_classic() +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS),
    legend.position = c(0.8, 0.8)  # Moves legend inside the plot (x, y relative coordinates)
  ) +
  guides(
    fill = guide_legend(
      keywidth = 0.2,  # Adjust the width of the legend keys
      keyheight = 0.2  # Adjust the height of the legend keys
    ))+
  scale_color_manual(values = rev(c("#777777", "#F28E2C")))

##########################################################

fileName <- paste0("binPeakDensity_RAD21_binaryGroup")
width <- 32*mmToInch
height <- 35*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

####### DOing this for P-S groups
resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene

# List of groups to process
groups <- c("psOver0", "psOver1", "psOver2", "psOver3", "psOver4")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "psOver0") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "psOver1") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "psOver2") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "psOver3")%>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "psOver4")

# Plot the results
p <- ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 0.5) +
  labs(
    x = "Distance bin (10kb)",
    y = "H3K4me3 peak count"
  ) +
  theme_classic() +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS),
    legend.position = c(0.8, 0.8)  # Moves legend inside the plot (x, y relative coordinates)
  ) +
  guides(
    fill = guide_legend(
      keywidth = 0.2,  # Adjust the width of the legend keys
      keyheight = 0.2  # Adjust the height of the legend keys
    ))+
  scale_color_manual(values = c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))

fileName <- paste0("binPeakDensity_RAD21_psGroup11")
width <- 32*mmToInch
height <- 35*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

### PE
peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene

# List of groups to process
groups <- c("peOver0", "peOver1", "peOver2", "peOver3", "peOver4")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "peOver0") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "peOver1") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "peOver2") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "peOver3")%>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "peOver4")

# Plot the results
ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 1) + xlim(0, 10)+
  labs(
    title = "Mean Peak Counts",
    x = "Distance Bin (10 kb)",
    y = "Mean Peak Counts"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.text = element_text(size = 12),
    axis.title = element_text(size = 13)
  )

###############
ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene

# List of groups to process
groups <- c("ppOver0", "ppOver1", "ppOver2", "ppOver3", "ppOver4")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "ppOver0") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "ppOver1") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "ppOver2") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "ppOver3")%>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "ppOver4")

# Plot the results
ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 1) +
  labs(
    title = "Mean Peak Counts",
    x = "Distance Bin (10 kb)",
    y = "Mean Peak Counts"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.text = element_text(size = 12),
    axis.title = element_text(size = 13)
  )

[2.31] Testing SEs?

peak.Whyte.SE <- importPeak(here(refDir, "superEnhancer_Whyte_ESC_mm10.bed"))
peak.Dylan.SE <- importPeak(here(refDir, "superEnhancer_Dylan_ESC.bed"))



flankSize <- 0.5e6
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6, V5)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl", "gene")

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

TSS1mb.group1.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group1), keep.extra.columns = TRUE)
TSS1mb.group2.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group2), keep.extra.columns = TRUE)


length(unique(queryHits(findOverlaps(TSS1mb.group1.gr, peak.Whyte.SE))))/length(gene.group1)*100
length(unique(queryHits(findOverlaps(TSS1mb.group2.gr, peak.Whyte.SE))))/length(gene.group2)*100

length(unique(queryHits(findOverlaps(TSS1mb.group1.gr, peak.Dylan.SE))))/length(gene.group1)*100
length(unique(queryHits(findOverlaps(TSS1mb.group2.gr, peak.Dylan.SE))))/length(gene.group2)*100

#View(as_tibble(TSS1mb.group1.gr[unique(queryHits(findOverlaps(TSS1mb.group1.gr, peak.Whyte.SE)))]))
#View(as_tibble(TSS1mb.group1.gr[unique(queryHits(findOverlaps(TSS1mb.group1.gr, peak.Dylan.SE)))]))

gene.group1.SE <- (as_tibble(TSS1mb.group1.gr[unique(queryHits(findOverlaps(TSS1mb.group1.gr, peak.Dylan.SE)))]))$ensembl
gene.group1.noSE <- gene.group1[!(gene.group1 %in% gene.group1.SE)]

overlaps <- findOverlaps(TSS1mb.group2.gr, peak.Dylan.SE)
unique_hits <- unique(queryHits(overlaps))
gene.group2.SE <- as_tibble(TSS1mb.group2.gr[unique_hits])$ensembl
gene.group2.noSE <- as_tibble(TSS1mb.group2.gr[-unique_hits])$ensembl


##########################################################
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - 1e6,
                TSSend = TSS + 1e6) %>%
  dplyr::select(V1, TSSstart, TSSend, V6, V5)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl", "gene")

##########################################################
# List of groups to process
groups <- c("gene.group1.SE", "gene.group1.noSE")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group1.SE") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group1.noSE")

# Plot the results
ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 1) +
  labs(
    title = paste0("Mean Peak Counts, +-", flankSize, "bp, Whyte SE"),
    x = "Distance Bin (10 kb)",
    y = "Mean Peak Counts"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.text = element_text(size = 12),
    axis.title = element_text(size = 13)
  )

##########################################################
# List of groups to process
groups <- c("gene.group1.SE", "gene.group1.noSE", "gene.group2.SE", "gene.group2.noSE")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
    add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group1.SE") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group1.noSE") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group2.SE") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group2.noSE")

# Plot the results
ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 1) +
  labs(
    title = paste0("Mean Peak Counts, +-", flankSize, "bp, Whyte SE"),
    x = "Distance Bin (10 kb)",
    y = "Mean Peak Counts"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.text = element_text(size = 12),
    axis.title = element_text(size = 13)
  )
##########################################################
# List of groups to process
groups <- c("gene.group2.SE", "gene.group2.noSE")

# Process each group and combine results
summary_data <- map_dfr(groups, ~ process_group(.x, gene.tb, bins.10kb))

# Add the additional rows for distanceBin = 0
summary_data <- summary_data %>%
  mutate(distanceBin = distanceBin + 1) %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group2.SE") %>%
  add_row(distanceBin = 0, mean_peak_counts = 0, sd_peak_counts = 0, group = "gene.group2.noSE")

# Plot the results
ggplot(summary_data, aes(x = distanceBin, y = mean_peak_counts, color = group)) + 
  geom_line(size = 1) +
  labs(
    title = paste0("Mean Peak Counts, +-", flankSize, "bp, Whyte SE"),
    x = "Distance Bin (10 kb)",
    y = "Mean Peak Counts"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.text = element_text(size = 12),
    axis.title = element_text(size = 13)
  )

## Checking P-S in the subset of genes

resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

temp3 <- temp2 %>% dplyr::filter(gene %in% c(gene.group1)) %>%
  dplyr::mutate(group = case_when(gene %in% gene.group1.SE ~ "SE",
                                  TRUE ~ "noSE"))


ggplot(temp3, aes(x = group, y = num_ps)) + geom_violin(aes(fill = group)) + geom_boxplot(width = 0.1) + theme_classic()

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$num_pp
  distance2 <- (data %>% dplyr::filter(group ==group2) )$num_pp
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


getPvalWilcox(temp3, "noSE", "SE")

[2.32] Checking directionality

name <- "chromo_cons_annoHierarchy"
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff)%>% 
  dplyr::mutate(distance = start2 - start1)


geneAnnoData <- geneAnnoData %>% unnest(gene)


gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, TSS)
colnames(gene.tb) <- c("ensembl", "TSS")


geneAnnoData  <- geneAnnoData %>% dplyr::left_join(gene.tb, by = c("gene" = "ensembl"))

data <- geneAnnoData %>% dplyr::select(c(1, 2, 3, 4, 5, 6, 29, 31, 35)) %>%
  rowwise() %>%
  dplyr::mutate(distToAnchor1 = (start1 + end1)/2 - TSS,
                distToAnchor2 = (start2 + end2)/2 - TSS,
                distToAnchor = if_else(abs(distToAnchor1) > abs(distToAnchor2), distToAnchor1, distToAnchor2),
                direction = if_else(distToAnchor > 0, "right", "left"))

data.directionality <- data %>% group_by(gene) %>%
  summarise(count = n(),
            n_right = sum(direction == "right"),
            n_left = sum(direction == "left")) %>%
  dplyr::filter(count > 1) %>%
  dplyr::mutate(n = n_right + n_left,
                directionality = abs((n_right - n_left)/n))


#ggplot(data.directionality, aes(x = directionality)) + geom_histogram() + theme_classic()


gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

temp <- data.directionality %>% dplyr::filter(gene %in% c(gene.group1, gene.group2)) %>%
  dplyr::mutate(group = if_else(gene %in% gene.group1, "group1", "group2"))


ggplot(temp, aes(x = group, y = directionality)) + geom_violin() + geom_boxplot(width = 0.1) + 
  geom_hline(yintercept = 0) + theme_classic() + ggtitle("P-S") +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")


#########################PS

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$directionality
  distance2 <- (data %>% dplyr::filter(group ==group2) )$directionality
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}


resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))
#####################

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene

temp <- data.directionality %>% dplyr::filter(gene %in% c(psOver0, psOver1, psOver2, psOver3, psOver4)) %>%
  dplyr::mutate(group = case_when(gene %in% psOver0 ~ "psOver0",
                                  gene %in% psOver1 ~ "psOver1",
                                  gene %in% psOver2 ~ "psOver2",
                                  gene %in% psOver3 ~ "psOver3",
                                  gene %in% psOver4 ~ "psOver4"))

p34 <- round(getPvalWilcox(temp, "psOver3", "psOver4"), 5)
p23 <- round(getPvalWilcox(temp, "psOver2", "psOver3"), 5)
p12 <- round(getPvalWilcox(temp, "psOver1", "psOver2"), 5)
p01 <- round(getPvalWilcox(temp, "psOver0", "psOver1"), 5)
p04 <- round(getPvalWilcox(temp, "psOver0", "psOver4"), 5)



ggplot(temp, aes(x = group, y = directionality)) + geom_violin() + geom_boxplot(width = 0.1) + 
  geom_hline(yintercept = 0) + theme_classic() + ggtitle("P-N") +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  annotate("text", x = 1, y = 0.5, label = paste0("p34: ", convPvalue(p34), "\n",
                                                "p23: ", convPvalue(p23), "\n",
                                                "p12: ", convPvalue(p12), "\n",
                                                "p01: ", convPvalue(p01), "\n",
                                                "p04: ", convPvalue(p04), "\n"),
           color = "black", hjust = 0, size = 3)


#################### pe

peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene

temp <- data.directionality %>% dplyr::filter(gene %in% c(peOver0, peOver1, peOver2, peOver3, peOver4)) %>%
  dplyr::mutate(group = case_when(gene %in% peOver0 ~ "peOver0",
                                  gene %in% peOver1 ~ "peOver1",
                                  gene %in% peOver2 ~ "peOver2",
                                  gene %in% peOver3 ~ "peOver3",
                                  gene %in% peOver4 ~ "peOver4"))

p34 <- round(getPvalWilcox(temp, "peOver3", "peOver4"), 5)
p23 <- round(getPvalWilcox(temp, "peOver2", "peOver3"), 5)
p12 <- round(getPvalWilcox(temp, "peOver1", "peOver2"), 5)
p01 <- round(getPvalWilcox(temp, "peOver0", "peOver1"), 5)
p04 <- round(getPvalWilcox(temp, "peOver0", "peOver4"), 5)



ggplot(temp, aes(x = group, y = directionality)) + geom_violin() + geom_boxplot(width = 0.1) + 
  geom_hline(yintercept = 0) + theme_classic() + ggtitle("P-N") +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  annotate("text", x = 1, y = 0.5, label = paste0("p34: ", convPvalue(p34), "\n",
                                                "p23: ", convPvalue(p23), "\n",
                                                "p12: ", convPvalue(p12), "\n",
                                                "p01: ", convPvalue(p01), "\n",
                                                "p04: ", convPvalue(p04), "\n"),
           color = "black", hjust = 0, size = 3)


#################### pp

ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene

temp <- data.directionality %>% dplyr::filter(gene %in% c(ppOver0, ppOver1, ppOver2, ppOver3, ppOver4)) %>%
  dplyr::mutate(group = case_when(gene %in% ppOver0 ~ "ppOver0",
                                  gene %in% ppOver1 ~ "ppOver1",
                                  gene %in% ppOver2 ~ "ppOver2",
                                  gene %in% ppOver3 ~ "ppOver3",
                                  gene %in% ppOver4 ~ "ppOver4"))

p34 <- round(getPvalWilcox(temp, "ppOver3", "ppOver4"), 5)
p23 <- round(getPvalWilcox(temp, "ppOver2", "ppOver3"), 5)
p12 <- round(getPvalWilcox(temp, "ppOver1", "ppOver2"), 5)
p01 <- round(getPvalWilcox(temp, "ppOver0", "ppOver1"), 5)
p04 <- round(getPvalWilcox(temp, "ppOver0", "ppOver4"), 5)



ggplot(temp, aes(x = group, y = directionality)) + geom_violin() + geom_boxplot(width = 0.1) + 
  geom_hline(yintercept = 0) + theme_classic() + ggtitle("P-N") +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  annotate("text", x = 1, y = 0.5, label = paste0("p34: ", convPvalue(p34), "\n",
                                                "p23: ", convPvalue(p23), "\n",
                                                "p12: ", convPvalue(p12), "\n",
                                                "p01: ", convPvalue(p01), "\n",
                                                "p04: ", convPvalue(p04), "\n"),
           color = "black", hjust = 0, size = 3)

[2.33] Checking guidance

name <- "chromo_cons_annoHierarchy"
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff)%>% 
  dplyr::mutate(distance = start2 - start1)

geneAnnoData <- geneAnnoData %>% unnest(gene)

gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, TSS)
colnames(gene.tb) <- c("ensembl", "TSS")


geneAnnoData  <- geneAnnoData %>% dplyr::left_join(gene.tb, by = c("gene" = "ensembl"))

data <- geneAnnoData %>% dplyr::select(c(1, 2, 3, 4, 5, 6, 29, 31, 35)) %>%
  rowwise() %>%
  dplyr::mutate(distToAnchor1 = (start1 + end1)/2 - TSS,
                distToAnchor2 = (start2 + end2)/2 - TSS,
                distToAnchor = if_else(abs(distToAnchor1) > abs(distToAnchor2), distToAnchor1, distToAnchor2),
                direction = if_else(distToAnchor > 0, "right", "left"))


result <- data %>%
  group_by(gene, direction) %>%
  mutate(distToAnchor = abs(distToAnchor)) %>%
  mutate(max_dist_P_S = ifelse(any(Anno2 == "P-S"), 
                               max(distToAnchor[Anno2 == "P-S"], na.rm = TRUE), 
                               NA)) %>%
  mutate(is_smaller = ifelse(is.na(max_dist_P_S), NA, 
                             ifelse(distToAnchor == max_dist_P_S, NA, distToAnchor < max_dist_P_S))) %>%
  ungroup()



result2 <- result %>% dplyr::filter(!is.na(is_smaller))

result3 <- result2 %>% group_by(gene, direction) %>%
  summarize(count_true = sum(is_smaller, na.rm = TRUE),
            count_false = sum(is_smaller == FALSE, na.rm = TRUE)) %>%
  dplyr::mutate(count = count_true + count_false,
                perc = count_true/count*100) %>%
  dplyr::select(gene, direction, perc)

result3 <- result3 %>% group_by(gene) %>% summarize(perc = mean(perc))

####### DOing this for P-S groups
resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% psOver0 ~ "psOver0",
                                            gene %in% psOver1 ~ "psOver1",
                                            gene %in% psOver2 ~ "psOver2",
                                            gene %in% psOver3 ~ "psOver3",
                                            gene %in% psOver4 ~ "psOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

####### DOing this for P-E groups
peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% peOver0 ~ "peOver0",
                                            gene %in% peOver1 ~ "peOver1",
                                            gene %in% peOver2 ~ "peOver2",
                                            gene %in% peOver3 ~ "peOver3",
                                            gene %in% peOver4 ~ "peOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

####### DOing this for P-P groups

ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% ppOver0 ~ "ppOver0",
                                            gene %in% ppOver1 ~ "ppOver1",
                                            gene %in% ppOver2 ~ "ppOver2",
                                            gene %in% ppOver3 ~ "ppOver3",
                                            gene %in% ppOver4 ~ "ppOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

result <- data %>%
  group_by(gene, direction) %>%
  mutate(distToAnchor = abs(distToAnchor)) %>%
  mutate(max_dist_P_S = ifelse(any(Anno2 == "P-S"), 
                               max(distToAnchor[Anno2 == "P-S"], na.rm = TRUE), 
                               NA))
result <- result %>% dplyr::filter(Anno2 != "P-S") %>%
  mutate(is_smaller = ifelse(is.na(max_dist_P_S), NA, 
                             ifelse(distToAnchor == max_dist_P_S, NA, distToAnchor < max_dist_P_S))) %>%
  ungroup()



result2 <- result %>% dplyr::filter(!is.na(is_smaller))

result3 <- result2 %>% group_by(gene, direction) %>%
  summarize(count_true = sum(is_smaller, na.rm = TRUE),
            count_false = sum(is_smaller == FALSE, na.rm = TRUE)) %>%
  dplyr::mutate(count = count_true + count_false,
                perc = count_true/count*100) %>%
  dplyr::select(gene, direction, perc)

result3 <- result3 %>% group_by(gene) %>% summarize(perc = mean(perc))

####### DOing this for P-S groups
resultDir <- here("../../result")
temp2 <- readRDS(here(resultDir, "gene_loop_link.rds"))

psOver4 <- (temp2 %>% dplyr::filter(num_ps >= 4))$gene
psOver3 <- (temp2 %>% dplyr::filter(num_ps >= 3, num_ps < 4))$gene
psOver2 <- (temp2 %>% dplyr::filter(num_ps >= 2, num_ps < 3))$gene
psOver1 <- (temp2 %>% dplyr::filter(num_ps >= 1, num_ps < 2))$gene
psOver0 <- (temp2 %>% dplyr::filter(num_ps < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% psOver0 ~ "psOver0",
                                            gene %in% psOver1 ~ "psOver1",
                                            gene %in% psOver2 ~ "psOver2",
                                            gene %in% psOver3 ~ "psOver3",
                                            gene %in% psOver4 ~ "psOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

####### DOing this for P-E groups
peOver4 <- (temp2 %>% dplyr::filter(num_pe >= 4))$gene
peOver3 <- (temp2 %>% dplyr::filter(num_pe >= 3, num_pe < 4))$gene
peOver2 <- (temp2 %>% dplyr::filter(num_pe >= 2, num_pe < 3))$gene
peOver1 <- (temp2 %>% dplyr::filter(num_pe >= 1, num_pe < 2))$gene
peOver0 <- (temp2 %>% dplyr::filter(num_pe < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% peOver0 ~ "peOver0",
                                            gene %in% peOver1 ~ "peOver1",
                                            gene %in% peOver2 ~ "peOver2",
                                            gene %in% peOver3 ~ "peOver3",
                                            gene %in% peOver4 ~ "peOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

####### DOing this for P-P groups

ppOver4 <- (temp2 %>% dplyr::filter(num_pp >= 4))$gene
ppOver3 <- (temp2 %>% dplyr::filter(num_pp >= 3, num_pp < 4))$gene
ppOver2 <- (temp2 %>% dplyr::filter(num_pp >= 2, num_pp < 3))$gene
ppOver1 <- (temp2 %>% dplyr::filter(num_pp >= 1, num_pp < 2))$gene
ppOver0 <- (temp2 %>% dplyr::filter(num_pp < 1))$gene


result4 <- result3 %>% dplyr::mutate(group = case_when(gene %in% ppOver0 ~ "ppOver0",
                                            gene %in% ppOver1 ~ "ppOver1",
                                            gene %in% ppOver2 ~ "ppOver2",
                                            gene %in% ppOver3 ~ "ppOver3",
                                            gene %in% ppOver4 ~ "ppOver4",
                                            TRUE ~ NA)) %>%
  dplyr::filter(!is.na(group))


ggplot(result4, aes(x =  group, y = perc)) + geom_violin() + geom_boxplot(width = 0.05) + theme_classic() +
  stat_summary(aes(group = group), fun = mean, geom = "point", shape = 21, size = 2, fill = "red", color = "black")

[2.34] Checking CTCF motif orientation

Calculating CTCF motif

peak.CTCF <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))

library(BSgenome.Mmusculus.UCSC.mm10)

# Extract sequences
sequences <- getSeq(BSgenome.Mmusculus.UCSC.mm10, peak.CTCF)


# Get the CTCF motif (or provide your own PWM)
ctcf_motif <- query(MotifDb, c("CTCF", "Mmusculus"))[[1]]

# Scan for the motif
motif_hits <- lapply(sequences, function(seq) {
    matchPWM(ctcf_motif, seq, min.score = "80%") # Adjust min.score as needed
})

motif_hits_reverse <- lapply(sequences, function(seq) {
    matchPWM(ctcf_motif, reverseComplement(seq), min.score = "80%")
})

# Combine results
result <- mapply(function(fwd, rev) {
    list(forward = fwd, reverse = rev)
}, motif_hits, motif_hits_reverse, SIMPLIFY = FALSE)


result[[5]]


result_tibble <- tibble(
    peak_id = seq_along(result), # Create an identifier for each peak
    alignment = map_chr(result, function(res) {
        has_fwd <- length(res$forward) > 0
        has_rev <- length(res$reverse) > 0
        
        if (has_fwd && has_rev) "fwdrev"
        else if (has_fwd) "fwd"
        else if (has_rev) "rev"
        else "none"
    })
)

temp <- as_tibble(peak.CTCF) %>% bind_cols(result_tibble) %>%
  dplyr::select(seqnames, start, end, alignment)

fwrite(temp, here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.motifAnnotated.bed"), col.names = FALSE, sep = "\t")

Comparing it to TSS

ctcf.peak <- fread(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.motifAnnotated.bed"))
colnames(ctcf.peak) <- c("chr", "start", "end", "motif")
ctcf.peak.gr <- makeGRangesFromDataFrame(ctcf.peak, keep.extra.columns = TRUE)


flankSize <- 1
gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V4, V5, V6)
colnames(gene.TSS.tb) <- c("chr", "start", "end", "strand", "gene", "ensembl")

tss.gr <- makeGRangesFromDataFrame(gene.TSS.tb, keep.extra.columns = TRUE)

fwd_peaks <- ctcf.peak.gr[ctcf.peak.gr$motif %in% c("fwd", "fwdrev")]
rev_peaks <- ctcf.peak.gr[ctcf.peak.gr$motif %in% c("rev", "fwdrev")]

# Find convergent CTCF pairs for each TSS
convergent_pairs <- lapply(seq_along(tss.gr), function(i) {
    current_tss <- tss.gr[i]
    
    # Filter peaks on the same chromosome as the TSS
    fwd_peaks_chr <- fwd_peaks[as.character(seqnames(fwd_peaks)) == as.character(seqnames(current_tss))]
    rev_peaks_chr <- rev_peaks[as.character(seqnames(rev_peaks)) == as.character(seqnames(current_tss))]
    
    # Find the closest forward peak to the left of the TSS
    left_fwd <- fwd_peaks_chr[start(fwd_peaks_chr) < start(current_tss)]
    closest_fwd <- if (length(left_fwd) > 0) {
      left_fwd[which.max(start(left_fwd))]
    } else {
      NA
    }
    
    # Find the closest reverse peak to the right of the TSS
    right_rev <- rev_peaks_chr[start(rev_peaks_chr) > start(current_tss)]
    closest_rev <- if (length(right_rev) > 0) {
      right_rev[which.min(start(right_rev))]
    } else {
      NA
    }
    
    # Combine results if both closest peaks exist
    if (!is.na(closest_fwd) && !is.na(closest_rev)) {
        tibble(
          chrom1 = as.character(seqnames(closest_fwd)),
          start1 = start(closest_fwd),
          end1 = end(closest_fwd),
          chrom2 = as.character(seqnames(closest_rev)),
          start2 = start(closest_rev),
          end2 = end(closest_rev),
          ensembl = current_tss$ensembl,
        )
    } else {
        NULL
    }
})

# Combine results into a tibble
result_tibble <- bind_rows(convergent_pairs)

fwrite(result_tibble, here(refDir, "tss_convergent_ctcf_motif_pairs.bedpe"), sep = "\t", col.names = FALSE)
fwrite(gene.TSS.tb %>% dplyr::select(c(1, 2, 3, 5)), here(refDir, "tss_2bp.bed"), sep = "\t", col.names = FALSE)

temp <- fread(here(refDir, "tss_convergent_ctcf_motif_pairs.bedpe")) %>% dplyr::filter(V7 == "Klf4")

fwrite(as_tibble(temp), here(refDir, "tss_convergent_ctcf_motif_pairs_klf4.bedpe"), sep = "\t", col.names = FALSE)

# Checking size distribution of ctcf pair
temp <- fread(here(refDir, "tss_convergent_ctcf_motif_pairs.bedpe"))
temp <- temp %>% dplyr::mutate(size = (V6 + V5)/2 - (V3 + V2)/2,
                       id = paste(V1, V2, V3, V5, V6, sep = "_"))
temp <- temp %>% dplyr::select(id, size) %>% distinct()

ggplot(temp, aes(x = size)) + geom_histogram() + scale_x_continuous(labels = label_kb_mb, limits = c(0, 1e6)) + scale_y_log10() + theme_classic() + ggtitle("size distribution of smallest convergent ctcf pairs around gene")

Filtering loops that fall within CTCF boundaries

flankSize <- 1
gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V4, V5, V6)
colnames(gene.TSS.tb) <- c("chr", "start", "end", "strand", "gene", "ensembl")
geneEnsemblPair <- gene.TSS.tb %>% dplyr::select(gene, ensembl)

boundary.pair <- fread(here(refDir, "tss_convergent_ctcf_motif_pairs.bedpe"))
colnames(boundary.pair) <- c("boundary_chrom1", "boundary_start1", "boundary_end1", "boundary_chrom2", "boundary_start2", "boundary_end2", "ensembl")
boundary.pair <- boundary.pair %>% dplyr::left_join(geneEnsemblPair, by = c("ensembl"))


# Importing loop gene annotation
name <- "chromo_cons_annoHierarchy"
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E")) %>%
  dplyr::select(c(1, 2, 3, 4, 5, 6, 11, 12, 24, 29, 31)) %>% unnest(gene)


data <- geneAnnoData %>% dplyr::left_join(boundary.pair, by = c("gene" = "ensembl"))

data <- data %>% rowwise() %>% dplyr::mutate(isWithinLeftBd = (boundary_start1 <= min(end1, end2)),
                       isWithinRightBd = (boundary_end2 >= max(start1, start2)),
                       isWithinBd = isWithinLeftBd & isWithinRightBd)
data <- data %>% drop_na()


ggplot(data, aes(x = DMSO, y = dTAG)) + geom_point() + coord_fixed() +  
  geom_abline(slope = 1, intercept = 0, col = "grey50", linetype = "dashed") +
  geom_hline(yintercept = 0, alpha = 0.5, color = "grey") +
  geom_vline(xintercept = 0, alpha = 0.5, color = "grey") +
  theme_classic() + facet_wrap(~ isWithinBd)

ggplot(data, aes(x = isWithinBd, y = diff_dTAG_DMSO, fill = isWithinBd)) + geom_violin() + geom_boxplot(width = 0.1) + theme_classic() +
  geom_hline(yintercept = 0)


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(isWithinBd ==group1) )$diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(isWithinBd ==group2) )$diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

getPvalWilcox(data, TRUE, FALSE)


# Proportion of those gene between group1 and group2
data.isWithinBd <- data %>% dplyr::filter(isWithinBd)

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

sum(gene.group1 %in% data.isWithinBd$gene)/length(gene.group1)*100

sum(gene.group2 %in% data.isWithinBd$gene)/length(gene.group2)*100

# Checking size of those loops
data <- data %>% dplyr::mutate(distance = start2 - start1)

ggplot(data, aes(x = isWithinBd, y = distance, fill = isWithinBd)) + geom_violin() + geom_boxplot(width = 0.1) + theme_classic()

[2.35] Checking CTCF motif presence at gene TSS

flankSize <- 2.5e3
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6, V5)
colnames(gene.tb) <- c("chr", "start", "end", "ensembl", "gene")

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

TSS1mb.group1.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group1), keep.extra.columns = TRUE)
TSS1mb.group2.gr <- makeGRangesFromDataFrame(gene.tb %>% dplyr::filter(ensembl %in% gene.group2), keep.extra.columns = TRUE)


ctcf.peak <- fread(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.motifAnnotated.bed"))
colnames(ctcf.peak) <- c("chr", "start", "end", "motif")
ctcf.peak.gr <- makeGRangesFromDataFrame(ctcf.peak)


print("+-2.5kb TSS overla with CTCF peak")
length(unique(queryHits(findOverlaps(TSS1mb.group1.gr, ctcf.peak.gr))))/length(gene.group1)*100
length(unique(queryHits(findOverlaps(TSS1mb.group2.gr, ctcf.peak.gr))))/length(gene.group2)*100



ctcf.peak.gr <- makeGRangesFromDataFrame(ctcf.peak %>% dplyr::filter(motif != "none"))
print("+-2.5kb TSS overla with CTCF peak with motif")
length(unique(queryHits(findOverlaps(TSS1mb.group1.gr, ctcf.peak.gr))))/length(gene.group1)*100
length(unique(queryHits(findOverlaps(TSS1mb.group2.gr, ctcf.peak.gr))))/length(gene.group2)*100

[2.36] Finding farthest P-S

name <- "chromo_cons_annoHierarchy"
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X")) %>%
  dplyr::select(c(1, 2, 3, 4, 5, 6, 7, 11, 12, 24, 29, 31)) %>% unnest(gene)


gene.TSS.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3)) %>%
  dplyr::select(V6, TSS)
colnames(gene.TSS.tb) <- c("ensembl", "TSS")


geneAnnoData <- geneAnnoData %>% dplyr::left_join(gene.TSS.tb, by = c("gene" = "ensembl"))

geneAnnoData <- geneAnnoData %>% 
  dplyr::mutate(distance1 = (start1 + end1)/2 - TSS,
                distance2 = (start2 + end2)/2 - TSS,
                distance = if_else(abs(distance1) > abs(distance2), distance1, distance2))

result <- geneAnnoData %>%
  filter(Anno2 == "P-S") %>%
  group_by(gene) %>%
  summarise(
    farRight = if (any(distance > 0)) max(distance[distance > 0]) else 0,  # Return 0 if no positive distance
    farLeft = if (any(distance < 0)) min(distance[distance < 0]) else 0  # Return 0 if no negative distance
  ) %>%
  ungroup()

geneAnnoData <- geneAnnoData %>% left_join(result, by = c("gene"))

geneAnnoData <- geneAnnoData %>% dplyr::filter(Anno2 %in% c("P-P", "P-E")) %>%
  dplyr::mutate(group = case_when(is.na(farRight) ~ "No",
                                  (distance > farLeft) & (distance < farRight) ~ "Within",
                                  TRUE ~ "Outside"),
                size = start2 - start1)

data <- geneAnnoData %>% dplyr::select(group, id, size) %>% distinct()
anchor.data <- geneAnnoData %>% dplyr::select(chrom1, start1, end1, chrom2, start2, end2, group) %>% distinct()

temp1 <- anchor.data %>% dplyr::filter(group == "No") %>% dplyr::select(-group)
fwrite(temp1, here(consensusDir, "insulated_domain_ps_no.bedpe"), sep = "\t", col.names = FALSE)
temp2 <- anchor.data %>% dplyr::filter(group == "Within") %>% dplyr::select(-group)
fwrite(temp2, here(consensusDir, "insulated_domain_ps_within.bedpe"), sep = "\t", col.names = FALSE)
temp3 <- anchor.data %>% dplyr::filter(group == "Outside") %>% dplyr::select(-group)
fwrite(temp3, here(consensusDir, "insulated_domain_ps_outside.bedpe"), sep = "\t", col.names = FALSE)


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$size
  distance2 <- (data %>% dplyr::filter(group ==group2) )$size
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

# convPvalue(getPvalWilcox(data, "noBoundary", "withinBoundary"))
# convPvalue(getPvalWilcox(data, "noBoundary", "outsideBoundary"))
# convPvalue(getPvalWilcox(data, "outsideBoundary", "withinBoundary"))


p <- ggplot(data, aes(x = group, y = size, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
                 linewidth = lineThick * mmToLineUnit, lineend = "square",
                 outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + scale_y_continuous(labels = label_kb_mb) +
  stat_summary(
      aes(group = group), fun = mean,
      geom = "point", shape = 21, size = 0.5,
      fill = "black", color = "black", position = position_dodge(.3)
    ) +
  scale_fill_manual(values = c("grey50", "#5EC962", "#5EC962")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Loop size")

fileName <- paste0("insulationBoundary_size")
width <- panelSize(1.5)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
  
########################
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(group ==group2) )$diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

data <- geneAnnoData %>% dplyr::select(group, id, diff_dTAG_DMSO) %>% distinct()

# convPvalue(getPvalWilcox(data, "noBoundary", "withinBoundary"))
# convPvalue(getPvalWilcox(data, "noBoundary", "outsideBoundary"))
# convPvalue(getPvalWilcox(data, "outsideBoundary", "withinBoundary"))

p <- ggplot(data, aes(x = group, y = diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "#5EC962", "#5EC962")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Δ loop score")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  geom_hline(yintercept = -0.2,
             alpha = 0.5, 
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square", linetype = "dashed") +
  coord_cartesian(ylim = c(-0.8, 0.5))
    
fileName <- paste0("insulationBoundary_delta")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  
  
  
 ###################### 
    
    minValue <- -4
  obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

geneAnnoData <- geneAnnoData %>% left_join(obsexp, by = c("id"))

data <- geneAnnoData %>% dplyr::select(group, id, log_obsexp_diff_dTAG_DMSO) %>% distinct()


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$log_obsexp_diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(group ==group2) )$log_obsexp_diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

# convPvalue(getPvalWilcox(data, "noBoundary", "withinBoundary"))
# convPvalue(getPvalWilcox(data, "noBoundary", "outsideBoundary"))
# convPvalue(getPvalWilcox(data, "outsideBoundary", "withinBoundary"))
# 

p <- ggplot(data, aes(x = group, y = log_obsexp_diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "#5EC962", "#5EC962")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "log2(fc of obs/exp)")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  coord_cartesian(ylim = c(-2, 2))
    
fileName <- paste0("insulationBoundary_obsexp")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  





#####################


gene.withinBoundary <- unique((geneAnnoData %>% dplyr::filter(group == "withinBoundary"))$gene)
gene.outsideBoundary <- unique((geneAnnoData %>% dplyr::filter(group == "outsideBoundary"))$gene)
gene.noBoundary <- unique((geneAnnoData %>% dplyr::filter(group == "noBoundary"))$gene)

gene.wBoundary <- unique(c(gene.withinBoundary, gene.outsideBoundary))

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

print("perc of gene with loop within Boundary")
sum(gene.group1 %in% gene.withinBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.withinBoundary)/length(gene.group2)*100

print("perc of gene with loop outside Boundary")
sum(gene.group1 %in% gene.outsideBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.outsideBoundary)/length(gene.group2)*100

print("perc of gene with loop with no Boundary")
sum(gene.group1 %in% gene.noBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.noBoundary)/length(gene.group2)*100


diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name) %>%
  dplyr::mutate(group = case_when(
    ensembl_gene_id %in% gene.wBoundary ~ "withinBoundary",
    ensembl_gene_id %in% gene.noBoundary ~ "noBoundary",
    TRUE ~ NA
  )) %>%
  dplyr::filter(!is.na(group)) %>%
  dplyr::mutate(absLog2FC = abs(log2FoldChange))


ggplot(diff.RNA, aes(x = group, y = log2FoldChange)) + geom_violin() + geom_boxplot(width = 0.1)

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$absLog2FC
  distance2 <- (data %>% dplyr::filter(group ==group2) )$absLog2FC
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}
convPvalue(getPvalWilcox(diff.RNA, "withinBoundary", "noBoundary"))


# Create the CDF plot
p <- ggplot(diff.RNA, aes(x = absLog2FC, color = group)) +
stat_ecdf(size = 0.4 ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Absolute log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 0.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )

fileName <- paste0("log2FC_cdf_insulationBoundary")
width <- panelSize(2.5)*mmToInch
height <- panelSize(1.5)*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()



### Checking characterstics of anchors
temp1 <- anchor.data %>% dplyr::filter(group == "noBoundary") %>% dplyr::select(-group)
anchor.noBoundary <- extractAnchor(temp1)

temp2 <- anchor.data %>% dplyr::filter(group == "withinBoundary") %>% dplyr::select(-group)
anchor.withinBoundary <- extractAnchor(temp2)

temp3 <- anchor.data %>% dplyr::filter(group == "outsideBoundary") %>% dplyr::select(-group)
anchor.outsideBoundary <- extractAnchor(temp3)


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(loop ==group1) )$sumScore
  distance2 <- (data %>% dplyr::filter(loop ==group2) )$sumScore
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

getSumScores <- function(track, anchor) {
  # Find overlaps between all anchors and track regions at once
  overlaps <- findOverlaps(anchor, track)
  
  # Extract the scores and corresponding anchor indices
  anchor_indices <- queryHits(overlaps)
  track_scores <- score(track)[subjectHits(overlaps)]
  
  # Use tapply to calculate the median scores for each anchor
  median_scores <- tapply(track_scores, anchor_indices, mean, na.rm = TRUE)
  
  # Initialize a numeric vector to store the median scores for each anchor
  all_median_scores <- rep(NA, length(anchor))
  
  # Populate the median scores for the anchors that have overlaps
  all_median_scores[as.numeric(names(median_scores))] <- median_scores
  
  return(all_median_scores)
}

plotSumScoresBinary <- function(track, peak, name, anchor1, anchor2, anchor3){
  peakTrack <- track[unique(queryHits(findOverlaps(track, peak)))]
  a <- getSumScores(peakTrack, anchor1)
  b <- getSumScores(peakTrack, anchor2)
  c <- getSumScores(peakTrack, anchor3)
  a.tb <- tibble(loop = "noBoundary",
                 sumScore = a)
  b.tb <- tibble(loop = "withBoundary",
                 sumScore = b)
  c.tb <- tibble(loop = "outsideBoundary",
                 sumScore = c)
  
  data <- bind_rows(a.tb, b.tb, c.tb) %>% drop_na()
  data$loop <- factor(data$loop, levels = c("noBoundary", "withBoundary", "outsideBoundary"))
  
  p12 <- getPvalWilcox(data, "noBoundary", "withBoundary")
  p13 <- getPvalWilcox(data, "noBoundary", "outsideBoundary")
  p23 <- getPvalWilcox(data, "withBoundary", "outsideBoundary")
  p <-  ggplot(data, aes(x = loop, y = sumScore)) + 
    labs(x = NULL, y = paste0(name, "\nlog(avg peak score per anchor)")) +
    geom_violin(aes(fill = loop), color = "black",
                linewidth = lineThick * mmToLineUnit, lineend = "square",
                show.legend = FALSE) +
    geom_boxplot(width = 0.1, color = "black",
                 linewidth = lineThick * mmToLineUnit, lineend = "square",
                 outlier.size = 1, outlier.stroke = NA) + theme_classic() +
    stat_summary(
      aes(group = loop), fun = mean,
      geom = "point", shape = 21, size = 1,
      fill = "red", color = "black"
    ) + theme(
      axis.title = element_text(
        size = fontSizeS, family = fontType, color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeS, family = fontType, color = "#000000"
      ),
      axis.text.x = element_text(
        angle = 45, hjust = 1, vjust = 1
      ),
      axis.line = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
      legend.text = element_text(family = fontType, size = fontSizeS),
      legend.title = element_text(family = fontType, size = fontSizeS)
    ) + 
    #coord_cartesian(ylim = c(quantile(data$sumScore, 0.0), quantile(data$sumScore, 0.99))) + 
    annotate(
      "text", x = 1, y = quantile(data$sumScore, 0.5),
      label = paste0("p12: ", convPvalue(p12), "\n",
                     "p13: ", convPvalue(p13), "\n",
                     "p23: ", convPvalue(p23)),
      color = "black", hjust = 0, size = 3
    ) 
  #+ scale_y_continuous(trans = "log10")
  
  fileName <- paste0("ChIP_peak_avgPeakScore_boundaryAnchor_", name)
  width <- panelSize(2)*mmToInch
  height <- panelSize(2)*mmToInch
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# Sum peak score
####
track <- import(here(refDir, "33255_H3K4me3_04-745_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33255_H3K4me3_04-745_Bruce-4_peaks.mergePeak.bed"))
plotSumScoresBinary(track, peak, "H3K4me3", anchor.noBoundary, anchor.withinBoundary, anchor.outsideBoundary)

track <- import(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2438476_EC-DG-3458-H3K27AC_ASYN_1.narrowPeak.bed"))
#plotSumScores(track, peak, "H3K27ac")
plotSumScoresBinary(track, peak, "H3K27ac", anchor.noBoundary, anchor.withinBoundary, anchor.outsideBoundary)

track <- import(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.black.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "GSM2683440_J1_H3K14ac_mm10Lifted.bed"))
#plotSumScores(track, peak, "H3K14ac")
plotSumScoresBinary(track, peak, "H3K14ac", anchor.noBoundary, anchor.withinBoundary, anchor.outsideBoundary)

track <- import(here(refDir, "33248_CTCF_07-729_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
#plotSumScores(track, peak, "CTCF")
plotSumScoresBinary(track, peak, "CTCF", anchor.noBoundary, anchor.withinBoundary, anchor.outsideBoundary)

track <- import(here(refDir, "33250_RAD21_ab992_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))
#plotSumScores(track, peak, "RAD21")
plotSumScoresBinary(track, peak, "RAD21", anchor.noBoundary, anchor.withinBoundary, anchor.outsideBoundary)



######## LOLA
atac <- fread(here(refDir, "GSM3106257_ATAC_ESC_1.bed")) %>% dplyr::select(V1, V2, V3)
colnames(atac) <- c("chr", "start", "end")
atac.gr <- makeGRangesFromDataFrame(atac)

# LOADING LOOPS
loop.all <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>% dplyr::filter(Anno2 %in% c("P-P", "P-E", "E-E"))
anchor.all <- (extractAnchor(loop.all))
overlaps <- findOverlaps(anchor.all, atac.gr)
anchor.all <- pintersect(anchor.all[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])

overlaps <- findOverlaps(anchor.noBoundary, atac.gr)
anchor.noBoundary <- pintersect(anchor.noBoundary[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
overlaps <- findOverlaps(anchor.withinBoundary, atac.gr)
anchor.withinBoundary <- pintersect(anchor.withinBoundary[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])
overlaps <- findOverlaps(anchor.outsideBoundary, atac.gr)
anchor.outsideBoundary <- pintersect(anchor.outsideBoundary[queryHits(overlaps)], atac.gr[subjectHits(overlaps)])



anchors <- list(anchor.noBoundary, anchor.withBoundary, anchor.outsideBoundary)
tbs <- list()
temps <- list()

alpha <- 0.05

# Process clusters c1 to c8
for (i in 1:3) {
  
  anchor <- anchors[[i]]
  # Run LOLA
  result <- runLOLA(anchor, anchor.all, lolaDB)
  tb <- as_tibble(result)
  
  # Filter and summarize
  tb <- tb %>%
    dplyr::mutate(target = toupper(antibody)) %>%
    filter(str_to_lower(cellType) == "embryonic stem cell") %>%
    dplyr::filter(qValue < alpha) %>%
    dplyr::group_by(target) %>%
    slice_min(meanRnk, with_ties = FALSE)
  
  # Store tb
  tbs[[i]] <- tb
  
  # Select and rename oddsRatio
  temp <- tb %>% dplyr::select(target, oddsRatio)
  colnames(temp) <- c("target", paste0("OR_c", i))
  
  # Store temp
  temps[[i]] <- temp
}

# Merge all temp tables into one
temp <- Reduce(function(x, y) full_join(x, y, by = "target"), temps) %>%
  mutate_all(~replace_na(., 1))
colnames(temp) <- c("target", "noBoundary", "withinBoundary", "outsideBoundary")
data <- temp %>% column_to_rownames("target") %>% as.matrix()

library(circlize)
col_fun <- colorRamp2(c(1, max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

[3.37] Checking RAD21 level at tss

tss.5kb.group1 <- fread(here(refDir, "TSS_binaryGroup1.bed")) %>%
  dplyr::mutate(start = (V2 + V3)/2 - 2500,
                end = (V2 + V3)/2 + 2500,
                chr = V1) %>%
  dplyr::select(chr, start, end)
tss.5kb.group1 <- makeGRangesFromDataFrame(tss.5kb.group1)

tss.5kb.group2 <- fread(here(refDir, "TSS_binaryGroup2.bed")) %>%
  dplyr::mutate(start = (V2 + V3)/2 - 2500,
                end = (V2 + V3)/2 + 2500,
                chr = V1) %>%
  dplyr::select(chr, start, end)
tss.5kb.group2 <- makeGRangesFromDataFrame(tss.5kb.group2)


plotSumScoresBinary <- function(track, peak, name, anchor1, anchor2){
  peakTrack <- track[unique(queryHits(findOverlaps(track, peak)))]
  a <- getSumScores(peakTrack, anchor1)
  b <- getSumScores(peakTrack, anchor2)
  a.tb <- tibble(loop = "group1",
                 sumScore = a)
  b.tb <- tibble(loop = "group2",
                 sumScore = b)
  
  data <- bind_rows(a.tb, b.tb) %>% drop_na()
  data$loop <- factor(data$loop, levels = c("group1", "group2"))
  
  p12 <- getPvalWilcox(data, "group1", "group2")
  p <-  ggplot(data, aes(x = loop, y = sumScore)) + 
    labs(x = NULL, y = paste0(name, "\nlog(avg peak score per anchor)")) +
    geom_violin(aes(fill = loop), color = "black",
                linewidth = lineThick * mmToLineUnit, lineend = "square",
                show.legend = FALSE) +
    geom_boxplot(width = 0.1, color = "black",
                 linewidth = lineThick * mmToLineUnit, lineend = "square",
                 outlier.size = 1, outlier.stroke = NA) + theme_classic() +
    stat_summary(
      aes(group = loop), fun = mean,
      geom = "point", shape = 21, size = 1,
      fill = "red", color = "black"
    ) + theme(
      axis.title = element_text(
        size = fontSizeS, family = fontType, color = "#000000"
      ),
      axis.text = element_text(
        size = fontSizeS, family = fontType, color = "#000000"
      ),
      axis.text.x = element_text(
        angle = 45, hjust = 1, vjust = 1
      ),
      axis.line = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      axis.ticks = element_line(
        color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
      ),
      panel.background = element_rect(fill = "transparent"),
      legend.text = element_text(family = fontType, size = fontSizeS),
      legend.title = element_text(family = fontType, size = fontSizeS)
    ) + 
    #coord_cartesian(ylim = c(quantile(data$sumScore, 0.0), quantile(data$sumScore, 0.99))) + 
    annotate(
      "text", x = 1, y = quantile(data$sumScore, 0.5),
      label = paste0("p12: ", convPvalue(p12)),
      color = "black", hjust = 0, size = 3
    ) 
  #+ scale_y_continuous(trans = "log10")
  
  fileName <- paste0("ChIP_peak_avgPeakScore_binaryGroup_", name)
  width <- panelSize(2)*mmToInch
  height <- panelSize(2)*mmToInch
  png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
  print(p)
  dev.off()
  svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
  print(p)
  dev.off()
}

# Sum peak score
####
track <- import(here(refDir, "33248_CTCF_07-729_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.bed"))
plotSumScoresBinary(track, peak, "CTCF", tss.5kb.group1, tss.5kb.group2)

track <- import(here(refDir, "33250_RAD21_ab992_Bruce-4_trim_q20_dedup_black_depthNorm.bw"), format = "BigWig")
peak <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))
plotSumScoresBinary(track, peak, "RAD21", tss.5kb.group1, tss.5kb.group2)

[3.38] Stripe percentage

# Create the data
data <- data.frame(
  Group = c("Group1", "Group2"),
  Value = c(31.03, 10.64)
)

# Create the bar plot
p <- ggplot(data, aes(x = Group, y = Value, fill = Group)) + 
  geom_bar(stat = "identity", color = "black", width = 0.7, alpha = 0.6, show.legend = FALSE,
           linewidth = lineThick * mmToLineUnit, lineend = "square") + # Use identity for raw values
  labs(y = "% of TSS on stripe") + 
  theme_classic() +
  theme(
    axis.title = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )

fileName <- paste0("perc_on_stripe_binaryGroup")
width <- panelSize(1.25)*mmToInch
height <- panelSize(1.2)*mmToInch
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

###[3.39] Splitting bedpe

temp <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>% dplyr::select(c(1, 2))
geneList <- (temp %>% dplyr::filter(external_gene_name %in% c("Klf4", "Tbx3", "Jun", "Fosl2", "Myc", "Phlda1")))$ensembl_gene_id

# LOAD ANNOTATED LOOP
name <- "chromo_cons_annoHierarchy"
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>%
  dplyr::mutate(distance = start2 - start1)

filteredLoop <- geneAnnoData %>% unnest(gene) %>% dplyr::filter(gene %in% geneList)
fwrite(filteredLoop, here(consensusDir, paste0("P-N_selectedGene.bedpe")), 
         sep = "\t", col.names = FALSE)
  
temploop <- filteredLoop %>% dplyr::filter(Anno2 %in% c("P-P", "P-E"))
fwrite(temploop, here(consensusDir, paste0("P-PE_selectedGene.bedpe")), 
         sep = "\t", col.names = FALSE)
  
temploop <- filteredLoop %>% dplyr::filter(Anno2 %in% c("P-S"))
fwrite(temploop, here(consensusDir, paste0("P-S_selectedGene.bedpe")), 
         sep = "\t", col.names = FALSE)

[3.40] Finding largest encompassing S-S

name <- "chromo_cons_annoHierarchy"

# IMPORT S-S loops
allLoops <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
strLoops <- allLoops %>% dplyr::filter(Anno2 %in% c("S-S"))
temp <- strLoops %>% dplyr::select(c(1, 2, 6))
colnames(temp) <- c("chrom", "start", "end")
strLoopsGr <- makeGRangesFromDataFrame(temp)

# IMPORT TSS
flankSize <- 10
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6, V5)
colnames(gene.tb) <- c("chrom", "start", "end", "ensembl", "gene")
geneGr <- makeGRangesFromDataFrame(gene.tb, keep.extra.columns = TRUE)


# Find overlaps between loops and TSS
overlaps <- findOverlaps(geneGr, strLoopsGr)

# Annotate overlaps
tss_with_loops <- geneGr[queryHits(overlaps)]
loops_with_tss <- strLoopsGr[subjectHits(overlaps)]

# Combine into a data frame for processing
loop_data <- data.frame(gene = tss_with_loops$ensembl,
                        loop_chr = seqnames(loops_with_tss),
                        loop_start = start(loops_with_tss),
                        loop_end = end(loops_with_tss),
                        loop_width = width(loops_with_tss))

# Identify the largest loop for each gene
largest_loops <- loop_data[order(loop_data$gene, -loop_data$loop_width), ]
largest_loops <- largest_loops[!duplicated(largest_loops$gene), ]
largest_loops <- largest_loops %>% dplyr::mutate(loopID = paste(loop_chr, loop_start, loop_end, sep = "_"))
largest_loops <- largest_loops[order(largest_loops$loop_chr, largest_loops$loop_start),]
rownames(largest_loops) <- NULL

# Checking smaller loops
allLoopsGr <- makeGRangesFromDataFrame(allLoops, 
                                       seqnames.field = "chrom1", 
                                       start.field = "start1", 
                                       end.field = "end2")
largestLoopsGr <- makeGRangesFromDataFrame(largest_loops, 
                                           seqnames.field = "loop_chr", 
                                           start.field = "loop_start", 
                                           end.field = "loop_end")
largestLoopsGr <- sort(unique(largestLoopsGr))
complete_overlaps <- subsetByOverlaps(allLoopsGr, largestLoopsGr, type = "within")
overlaps <- findOverlaps(complete_overlaps, largestLoopsGr)


completeOverlapDf <- as.data.frame(complete_overlaps) %>% dplyr::mutate(loopIDAll = paste(seqnames, start, end, sep = "_"))
largestLoopsDf <- as.data.frame(largestLoopsGr) %>% dplyr::mutate(loopID = paste(seqnames, start, end, sep = "_"))

loopIDpairs <- data.frame(loopID = completeOverlapDf$loopIDAll[queryHits(overlaps)],
                          loopID2 = largestLoopsDf$loopID[subjectHits(overlaps)])

allLoopsAnnotated <- allLoops %>% dplyr::mutate(loopID = paste(chrom1, start1, end2, sep = "_")) %>% dplyr::left_join(loopIDpairs, by = c("loopID"))

temp <- allLoopsAnnotated %>% dplyr::filter(Anno2 %in% c("P-E", "P-P", "E-E")) %>% dplyr::mutate(hasSS = !is.na(loopID2))
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(hasSS ==group1) )$diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(hasSS ==group2) )$diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}
pv <- convPvalue(getPvalWilcox(temp, TRUE, FALSE))
ggplot(temp, aes(x = hasSS, y = diff_dTAG_DMSO)) + geom_violin(aes(fill = hasSS), show.legend = FALSE) + 
  geom_boxplot(width = 0.1, outlier.shape = NA) +
  stat_summary(aes(group = hasSS), fun = mean, 
               geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  theme_classic() +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black") +
  ggtitle("PE-PE") + geom_hline(yintercept = 0)


# Counting loop types
allLoopsAnnotatedFiltered <- allLoopsAnnotated %>% dplyr::filter(!is.na(loopID2)) %>%
  dplyr::filter(!(loopID == loopID2))
temp <- allLoopsAnnotatedFiltered %>% dplyr::select(loopID2, Anno2)
result <- temp %>%
  group_by(loopID2, Anno2) %>%
  summarise(count = n(), .groups = 'drop') %>%
  group_by(loopID2) %>%
  mutate(frequency = count / sum(count)) %>%
  arrange(loopID2, Anno2)

result <- largest_loops %>% dplyr::left_join(result, by = c("loopID" = "loopID2"))

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(result, by = c("gene"))
data <- data %>% filter(complete.cases(.))

all_anno2 <- unique(data$Anno2)

# Calculate average frequency of Anno2 for each gene in each group
result <- data %>%
  # Ensure all possible Anno2 values are present for each gene and group
  complete(gene, Anno2 = all_anno2, fill = list(frequency = 0)) %>% 
  dplyr::mutate(group = case_when(
    gene %in% gene.group1 ~ "group1",
    gene %in% gene.group2 ~ "group2",
    TRUE ~ NA
  )) %>%
  dplyr::select(group, Anno2, frequency)
  

ggplot(result, aes(x = Anno2, fill = group, y = frequency)) + geom_boxplot()
# View results
ggplot(largest_loops, aes(x = loop_width)) + geom_histogram()


### Checking how many genes from each group has encompassing S-S
gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(largest_loops, by = c("gene"))
data <- data %>% dplyr::mutate(
  hasSS = ifelse(is.na(loop_width), "NO", "YES")
)

data_summary <- data %>%
  group_by(group) %>%
  summarize(
    total = n(),
    hasSS_yes = sum(hasSS == "YES"),
    percentage_yes = (hasSS_yes / total) * 100
  )

ggplot(data_summary, aes(x = group, y = percentage_yes, fill = group)) +
  geom_bar(stat = "identity", color = "black") +
  labs(
    title = "Percentage of Each Group with hasSS = YES",
    x = "Group",
    y = "Percentage (%)"
  ) + ylim(0, 100) +
  theme_minimal()


temp <- data %>% dplyr::filter(hasSS == "YES")
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$loop_width
  distance2 <- (data %>% dplyr::filter(group ==group2) )$loop_width
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}
pv <- convPvalue(getPvalWilcox(temp, "group1", "group2"))

ggplot(temp, aes(x = group, y = loop_width)) + geom_violin() + geom_boxplot(width = 0.5) +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black")

### Comparing RNA perturbation

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(c(1, 4, 5)) %>%
  dplyr::mutate(hasSS = ifelse(ensembl_gene_id %in% largest_loops$gene, "hasSS", "noSS"))


ggplot(diff.RNA, aes(x = abs(log2FoldChange), color = hasSS)) +
  stat_ecdf(size = 0.4) +
  labs(
    x = "Absolute log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )


### Checking ChIP peak density
largest_loopsGr <- makeGRangesFromDataFrame(largest_loops, 
                                            seqnames.field = "loop_chr", 
                                            start.field = "loop_start", 
                                            end.field = "loop_end", 
                                            keep.extra.columns = TRUE)

# Find overlaps between ChIP-seq peaks and the largest loops
chip_overlaps <- findOverlaps(largest_loopsGr, peak.CTCF)

# Count the number of ChIP-seq peaks per loop
loop_peak_counts <- table(queryHits(chip_overlaps))

# Create a data frame with the counts and loop details
largest_loops$density <- 0  # Initialize density column
largest_loops$count <- 0    # Initialize peak count column

# Add peak counts to the corresponding loops
largest_loops[as.numeric(names(loop_peak_counts)), "count"] <- as.integer(loop_peak_counts)

# Calculate the density (peaks per kilobase)
largest_loops$density <- largest_loops$count / ((largest_loops$loop_width-1) / 1000)


data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(largest_loops, by = c("gene"))
data <- data %>% dplyr::mutate(
  hasSS = ifelse(is.na(loop_width), "NO", "YES")
) %>% dplyr::filter(hasSS == "YES")

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$density
  distance2 <- (data %>% dplyr::filter(group ==group2) )$density
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pv <- convPvalue(getPvalWilcox(data, "group1", "group2"))

ggplot(data, aes(x = group, y = density)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
  geom_boxplot(width = 0.1, outlier.shape = NA) +
  stat_summary(aes(group = group), fun = mean, 
               geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  theme_classic() +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black") +
  ggtitle("CTCF")

[3.41] Finding largest convergent encompassing S-S

Filtering convergent S-S loops

name <- "chromo_cons_annoHierarchy"

# IMPORT S-S LOOPS
allLoops <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv"))
strLoops <- allLoops %>% dplyr::filter(Anno2 %in% c("S-S"))
temp <- strLoops %>% dplyr::select(c(1, 2, 3, 5, 6))  # Assuming columns include anchor positions
colnames(temp) <- c("chrom", "start1", "end1", "start2", "end2")
strLoopsGr1 <- makeGRangesFromDataFrame(
  temp %>% dplyr::select(chrom, start = start1, end = end1)
)
strLoopsGr2 <- makeGRangesFromDataFrame(
  temp %>% dplyr::select(chrom, start = start2, end = end2)
)

# IMPORT CTCF MOTIF ANNOTATION
ctcfMotifs <- fread(here(refDir, "33248_CTCF_07-729_Bruce-4_peaks.mergePeak.motifAnnotated.bed"))
colnames(ctcfMotifs) <- c("chrom", "start", "end", "motif")
ctcfGr <- makeGRangesFromDataFrame(ctcfMotifs, keep.extra.columns = TRUE)

# Annotate each loop anchor with CTCF motifs
anchor1_with_ctcf <- findOverlaps(strLoopsGr1, ctcfGr)
anchor2_with_ctcf <- findOverlaps(strLoopsGr2, ctcfGr)

# Get motif information for anchor1 overlaps
anchor1_ctcf_motif <- rep(NA, length(strLoopsGr1))  # Initialize motif vector
anchor1_ctcf_motif[queryHits(anchor1_with_ctcf)] <- ctcfGr[subjectHits(anchor1_with_ctcf)]$motif

# Get motif information for anchor2 overlaps
anchor2_ctcf_motif <- rep(NA, length(strLoopsGr2))  # Initialize motif vector
anchor2_ctcf_motif[queryHits(anchor2_with_ctcf)] <- ctcfGr[subjectHits(anchor2_with_ctcf)]$motif

# Add motif information to strLoops
strLoops <- strLoops %>%
  mutate(
    anchor1_motif = anchor1_ctcf_motif,
    anchor2_motif = anchor2_ctcf_motif
  )

# Filter for convergent CTCF interactions (forward in anchor1, reverse in anchor2)
convergent_loops <- strLoops %>%
  filter(anchor1_motif == "fwd" & anchor2_motif == "rev") %>% dplyr::filter(Anno2 %in% c("S-S"))

Processing

# Extract loop boundary from left to right
temp <- convergent_loops %>% dplyr::select(c(1, 2, 6))
colnames(temp) <- c("chrom", "start", "end")
strLoopsGr <- makeGRangesFromDataFrame(temp)

# IMPORT TSS
flankSize <- 10
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V1, TSSstart, TSSend, V6, V5)
colnames(gene.tb) <- c("chrom", "start", "end", "ensembl", "gene")
geneGr <- makeGRangesFromDataFrame(gene.tb, keep.extra.columns = TRUE)


# Find overlaps between loops and TSS
overlaps <- findOverlaps(geneGr, strLoopsGr)

# Annotate overlaps
tss_with_loops <- geneGr[queryHits(overlaps)]
loops_with_tss <- strLoopsGr[subjectHits(overlaps)]

# Combine into a data frame for processing
loop_data <- data.frame(gene = tss_with_loops$ensembl,
                        loop_chr = seqnames(loops_with_tss),
                        loop_start = start(loops_with_tss),
                        loop_end = end(loops_with_tss),
                        loop_width = width(loops_with_tss))

# Identify the largest loop for each gene
largest_loops <- loop_data[order(loop_data$gene, -loop_data$loop_width), ]
largest_loops <- largest_loops[!duplicated(largest_loops$gene), ]
largest_loops <- largest_loops %>% dplyr::mutate(loopID = paste(loop_chr, loop_start, loop_end, sep = "_"))
largest_loops <- largest_loops[order(largest_loops$loop_chr, largest_loops$loop_start),]
rownames(largest_loops) <- NULL

# Checking smaller loops
allLoopsGr <- makeGRangesFromDataFrame(allLoops, 
                                       seqnames.field = "chrom1", 
                                       start.field = "start1", 
                                       end.field = "end2")
largestLoopsGr <- makeGRangesFromDataFrame(largest_loops, 
                                           seqnames.field = "loop_chr", 
                                           start.field = "loop_start", 
                                           end.field = "loop_end")
largestLoopsGr <- sort(unique(largestLoopsGr))
complete_overlaps <- subsetByOverlaps(allLoopsGr, largestLoopsGr, type = "within")
overlaps <- findOverlaps(complete_overlaps, largestLoopsGr)


completeOverlapDf <- as.data.frame(complete_overlaps) %>% dplyr::mutate(loopIDAll = paste(seqnames, start, end, sep = "_"))
largestLoopsDf <- as.data.frame(largestLoopsGr) %>% dplyr::mutate(loopID = paste(seqnames, start, end, sep = "_"))

loopIDpairs <- data.frame(loopID = completeOverlapDf$loopIDAll[queryHits(overlaps)],
                          loopID2 = largestLoopsDf$loopID[subjectHits(overlaps)])

# allLoopsAnnotated <- allLoops %>% dplyr::mutate(loopID = paste(chrom1, start1, end2, sep = "_")) %>% dplyr::left_join(loopIDpairs, by = c("loopID"))


##################################
diffCutoff <- 0.2
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = diffCutoff,
                                      annoList = c("P-P", "P-E", "P-S", "P-X")) %>% unnest(gene) %>%
  dplyr::mutate(loopID = paste(chrom1, start1, end2, sep = "_"))
temp <- geneAnnoData %>% dplyr::left_join(loopIDpairs, by = c("loopID"))
temp2 <- temp %>% dplyr::select(gene, loopID2) %>%
  group_by(gene) %>%              # Group data by the 'gene' column
  summarize(geneHasSS = !all(is.na(loopID2)))  # Check if all loopID2 values for each gene are NA
temp <- temp %>% left_join(temp2, by = c("gene"))
data.all <- temp %>% dplyr::mutate(group = ifelse(!geneHasSS, "No",
                                              ifelse(is.na(loopID2), "Outside", "Within")),
                               size = start2 - start1)

##################################
outfile <- data.all %>% dplyr::select(loopID2, gene) %>% dplyr::filter(!is.na(loopID2)) %>%
  separate(loopID2, into = c("chrom", "start", "end"), sep = "_", convert = TRUE)
# fwrite(outfile, here(consensusDir, "convergent_ss_domain.bed"), sep = "\t", col.names = FALSE)

Plotting

data <- data.all %>% dplyr::filter(Anno2 %in% c("P-E"))

temp <- data %>% dplyr::select(chrom1, start1, end1, chrom2, start2, end2, group) %>% distinct()

temp1 <- temp %>% dplyr::filter(group == "No") %>% dplyr::select(-group)
fwrite(temp1, here(consensusDir, "insulated_domain_ss_no.bedpe"), sep = "\t", col.names = FALSE)
temp2 <- temp %>% dplyr::filter(group == "Within") %>% dplyr::select(-group)
fwrite(temp2, here(consensusDir, "insulated_domain_ss_within.bedpe"), sep = "\t", col.names = FALSE)
temp3 <- temp %>% dplyr::filter(group == "Outside") %>% dplyr::select(-group)
fwrite(temp3, here(consensusDir, "insulated_domain_ss_outside.bedpe"), sep = "\t", col.names = FALSE)

temp <- data %>% dplyr::select(id, group, size) %>% distinct()


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$size
  distance2 <- (data %>% dplyr::filter(group ==group2) )$size
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

convPvalue(getPvalWilcox(temp, "No", "Within"))
convPvalue(getPvalWilcox(temp, "No", "Outside"))
convPvalue(getPvalWilcox(temp, "Outside", "Within"))


p <- ggplot(temp, aes(x = group, y = size, fill = group)) + 
  geom_violin(linewidth = lineMedium* mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
                 linewidth = lineMedium * mmToLineUnit, lineend = "square",
                 outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + scale_y_continuous(labels = label_kb_mb) +
  scale_fill_manual(values = c("#777777", "#F28E2C", "#F28E2C")) +
  stat_summary(
      aes(group = group), fun = mean,
      geom = "point", shape = 21, size = 0.5,
      fill = "black", color = "black", position = position_dodge(.3)
  ) +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Loop size")

fileName <- paste0("insulationBoundary_size_convSS_PE")
width <-33*mmToInch
height <- 35*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(group ==group2) )$diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

temp <- data %>% dplyr::select(group, id, diff_dTAG_DMSO) %>% distinct()

convPvalue(getPvalWilcox(temp, "No", "Within"))
convPvalue(getPvalWilcox(temp, "No", "Outside"))
convPvalue(getPvalWilcox(temp, "Outside", "Within"))

p <- ggplot(data, aes(x = group, y = diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineMedium * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() +   
    scale_fill_manual(values = c("#777777", "#F28E2C", "#F28E2C")) +
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Δ loop score") +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  geom_hline(yintercept = -0.2,
             alpha = 0.5, 
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square", linetype = "dashed") +
  coord_cartesian(ylim = c(-0.8, 0.5))
    
fileName <- paste0("insulationBoundary_delta_convSS_pe")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  


###################### 

minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

data2 <- data %>% left_join(obsexp, by = c("id"))

temp <- data2 %>% dplyr::select(group, id, log_obsexp_diff_dTAG_DMSO) %>% distinct()


getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$log_obsexp_diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(group ==group2) )$log_obsexp_diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

convPvalue(getPvalWilcox(temp, "No", "Within"))
convPvalue(getPvalWilcox(temp, "No", "Outside"))
convPvalue(getPvalWilcox(temp, "Outside", "Within"))


p <- ggplot(temp, aes(x = group, y = log_obsexp_diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineMedium* mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  scale_fill_manual(values = c("#777777", "#F28E2C", "#F28E2C")) +
  
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "log2(fc of obs/exp)") +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  coord_cartesian(ylim = c(-2, 2))
    width <-30*mmToInch
height <- 35*mmToInch
fileName <- paste0("insulationBoundary_obsexp_convSS_pe")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  





#####################

data <- data.all
gene.withinBoundary <- unique((data %>% dplyr::filter(group == "Within"))$gene)
gene.outsideBoundary <- unique((data %>% dplyr::filter(group == "Outside"))$gene)
gene.noBoundary <- unique((data %>% dplyr::filter(group == "No"))$gene)

gene.wBoundary <- unique(c(gene.withinBoundary, gene.outsideBoundary))

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

print("perc of gene with loop within Boundary")
sum(gene.group1 %in% gene.withinBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.withinBoundary)/length(gene.group2)*100

print("perc of gene with loop outside Boundary")
sum(gene.group1 %in% gene.outsideBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.outsideBoundary)/length(gene.group2)*100

print("perc of gene with loop with no Boundary")
sum(gene.group1 %in% gene.noBoundary)/length(gene.group1)*100
sum(gene.group2 %in% gene.noBoundary)/length(gene.group2)*100


diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name) %>%
  dplyr::mutate(group = case_when(
    ensembl_gene_id %in% gene.wBoundary ~ "withinBoundary",
    ensembl_gene_id %in% gene.noBoundary ~ "noBoundary",
    TRUE ~ NA
  )) %>%
  dplyr::filter(!is.na(group)) %>%
  dplyr::mutate(absLog2FC = abs(log2FoldChange))
ks_result <- ks.test(
  diff.RNA %>% dplyr::filter(group == "withinBoundary") %>% pull(absLog2FC),
  diff.RNA %>% dplyr::filter(group == "noBoundary") %>% pull(absLog2FC)
)

ggplot(diff.RNA, aes(x = group, y = log2FoldChange)) + geom_violin() + geom_boxplot(width = 0.1)

# getPvalWilcox <- function(data, group1, group2){
#   distance1 <- (data %>% dplyr::filter(group ==group1) )$absLog2FC
#   distance2 <- (data %>% dplyr::filter(group ==group2) )$absLog2FC
#   wil <- wilcox.test(distance1, distance2)
#   return(wil$p.value)
# }
# convPvalue(getPvalWilcox(diff.RNA, "withBoundary", "noBoundary"))
# 

# Create the CDF plot
p <- ggplot(diff.RNA, aes(x = absLog2FC, color = group)) +
  scale_color_manual(values = (c("#777777", "#F28E2C"))) +

stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square"  ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )

fileName <- paste0("log2FC_cdf_insulationBoundary_convSS_pe")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
temp <- allLoopsAnnotated %>% dplyr::filter(Anno2 %in% c("P-E")) %>% dplyr::mutate(hasSS = !is.na(loopID2))
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(hasSS ==group1) )$diff_dTAG_DMSO
  distance2 <- (data %>% dplyr::filter(hasSS ==group2) )$diff_dTAG_DMSO
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}
pv <- convPvalue(getPvalWilcox(temp, TRUE, FALSE))
ggplot(temp, aes(x = hasSS, y = diff_dTAG_DMSO)) + geom_violin(aes(fill = hasSS), show.legend = FALSE) + 
  geom_boxplot(width = 0.1, outlier.shape = NA) +
  stat_summary(aes(group = hasSS), fun = mean, 
               geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  theme_classic() +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black") +
  ggtitle("PE") + geom_hline(yintercept = 0)




# Counting loop types
allLoopsAnnotatedFiltered <- allLoopsAnnotated %>% dplyr::filter(!is.na(loopID2)) %>%
  dplyr::filter(!(loopID == loopID2))
temp <- allLoopsAnnotatedFiltered %>% dplyr::select(loopID2, Anno2)
result <- temp %>%
  group_by(loopID2, Anno2) %>%
  summarise(count = n(), .groups = 'drop') %>%
  group_by(loopID2) %>%
  mutate(frequency = count / sum(count)) %>%
  arrange(loopID2, Anno2)

result <- largest_loops %>% dplyr::left_join(result, by = c("loopID" = "loopID2"))

gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(result, by = c("gene"))
data <- data %>% filter(complete.cases(.))

all_anno2 <- unique(data$Anno2)

# Calculate average frequency of Anno2 for each gene in each group
result <- data %>%
  # Ensure all possible Anno2 values are present for each gene and group
  complete(gene, Anno2 = all_anno2, fill = list(frequency = 0)) %>% 
  dplyr::mutate(group = case_when(
    gene %in% gene.group1 ~ "group1",
    gene %in% gene.group2 ~ "group2",
    TRUE ~ NA
  )) %>%
  dplyr::select(group, Anno2, frequency)
  

ggplot(result, aes(x = Anno2, fill = group, y = frequency)) + geom_boxplot()



# View results
ggplot(largest_loops, aes(x = loop_width)) + geom_histogram()


### Checking how many genes from each group has encompassing S-S
gene.group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
gene.group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(largest_loops, by = c("gene"))
data <- data %>% dplyr::mutate(
  hasSS = ifelse(is.na(loop_width), "NO", "YES")
)

data_summary <- data %>%
  group_by(group) %>%
  summarize(
    total = n(),
    hasSS_yes = sum(hasSS == "YES"),
    percentage_yes = (hasSS_yes / total) * 100
  )

ggplot(data_summary, aes(x = group, y = percentage_yes, fill = group)) +
  geom_bar(stat = "identity", color = "black") +
  labs(
    title = "Percentage of Each Group with hasSS = YES",
    x = "Group",
    y = "Percentage (%)"
  ) + ylim(0, 100) +
  theme_minimal()

temp <- data %>% dplyr::filter(hasSS == "YES")
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$loop_width
  distance2 <- (data %>% dplyr::filter(group ==group2) )$loop_width
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}
pv <- convPvalue(getPvalWilcox(temp, "group1", "group2"))

ggplot(temp, aes(x = group, y = loop_width)) + geom_violin() + geom_boxplot(width = 0.5) +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black")


### Comparing RNA perturbation

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(c(1, 4, 5)) %>%
  dplyr::mutate(hasSS = ifelse(ensembl_gene_id %in% largest_loops$gene, "hasSS", "noSS"))


ggplot(diff.RNA, aes(x = abs(log2FoldChange), color = hasSS)) +
  stat_ecdf(size = 0.4) +
  labs(
    x = "Absolute log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    )



### Checking ChIP peak density
largest_loopsGr <- makeGRangesFromDataFrame(largest_loops, 
                                            seqnames.field = "loop_chr", 
                                            start.field = "loop_start", 
                                            end.field = "loop_end", 
                                            keep.extra.columns = TRUE)

# Find overlaps between ChIP-seq peaks and the largest loops
chip_overlaps <- findOverlaps(largest_loopsGr, peak.H3K4me3)

# Count the number of ChIP-seq peaks per loop
loop_peak_counts <- table(queryHits(chip_overlaps))

# Create a data frame with the counts and loop details
largest_loops$density <- 0  # Initialize density column
largest_loops$count <- 0    # Initialize peak count column

# Add peak counts to the corresponding loops
largest_loops[as.numeric(names(loop_peak_counts)), "count"] <- as.integer(loop_peak_counts)

# Calculate the density (peaks per kilobase)
largest_loops$density <- largest_loops$count / ((largest_loops$loop_width-1) / 1000)


data <- tibble(
  gene = c(gene.group1, gene.group2),
  group = c(rep("group1", length(gene.group1)),
            rep("group2", length(gene.group2)))
)

data <- data %>% dplyr::left_join(largest_loops, by = c("gene"))
data <- data %>% dplyr::mutate(
  hasSS = ifelse(is.na(loop_width), "NO", "YES")
) %>% dplyr::filter(hasSS == "YES")

getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(group ==group1) )$density
  distance2 <- (data %>% dplyr::filter(group ==group2) )$density
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

pv <- convPvalue(getPvalWilcox(data, "group1", "group2"))

ggplot(data, aes(x = group, y = density)) + geom_violin(aes(fill = group), show.legend = FALSE) + 
  geom_boxplot(width = 0.1, outlier.shape = NA) +
  stat_summary(aes(group = group), fun = mean, 
               geom = "point", shape = 21, size = 2, fill = "red", color = "black") +
  theme_classic() +
  annotate("text", x = 1, y = 0, label = pv, size = 5, color = "black") +
  ggtitle("H3K4me3")

[3.42] Comparing to Reg loops to A485

name <- "chromo_cons_annoHierarchy"
# UP loop
loop.up <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_UP_diff0.2.bedpe")) %>%
  dplyr::mutate(loopID = paste(V1, V2, V6, sep = "_"))
# NO loop
loop.no <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_NO_diff0.2.bedpe")) %>%
  dplyr::mutate(loopID = paste(V1, V2, V6, sep = "_"))
# UP NO
loop.upno <- bind_rows(loop.up, loop.no)
# DOWN loop
loop.down <- fread(here(consensusDir, "chromo_cons_annoHierarchy_pe-pe_dTAGvsDMSO_DOWN_diff0.2.bedpe")) %>%
  dplyr::mutate(loopID = paste(V1, V2, V6, sep = "_"))


allLoops <- fread(here(consensusDir, "chromo_cons_annoHierarchy.tsv")) %>%
  dplyr::mutate(loopID = paste(chrom1, start1, end2, sep = "_")) %>%
  dplyr::mutate(group = case_when(
    loopID %in% loop.upno$loopID ~ "UP&NO",
    loopID %in% loop.down$loopID ~ "DOWN",
    TRUE ~ NA
  )) %>%
  dplyr::filter(!is.na(group))

minValue <- -4
obsexp <- fread(here(consensusDir, paste0("loopScore_cons_obsexp.tsv"))) %>%
  dplyr::mutate(log_obsexp_DMSO = if_else(obsexp_DMSO == 0, minValue, log2(obsexp_DMSO)),
                log_obsexp_dTAG = if_else(obsexp_dTAG == 0, minValue, log2(obsexp_dTAG)),
                log_obsexp_A485 = if_else(obsexp_A485 == 0, minValue, log2(obsexp_A485)),
                log_obsexp_diff_dTAG_DMSO = log_obsexp_dTAG - log_obsexp_DMSO,
                log_obsexp_diff_A485_DMSO = log_obsexp_A485 - log_obsexp_DMSO)

allLoops <- allLoops %>% left_join(obsexp, by = c("id"))
allLoops$group <- factor(allLoops$group, levels = c("UP&NO", "DOWN"))


### Plotting
p1 <- ggplot(allLoops, aes(x = group, y = diff_A485_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "grey50")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Δ loop score")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  geom_hline(yintercept = -0.2,
             alpha = 0.5, 
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square", linetype = "dashed") +
  coord_cartesian(ylim = c(-0.5, 0.5))
    

####
p2 <- ggplot(allLoops, aes(x = group, y = log_obsexp_diff_A485_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "grey50")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "log2(fc of obs/exp)")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  coord_cartesian(ylim = c(-2, 2))
  


#############

### Plotting
p3 <- ggplot(allLoops, aes(x = group, y = diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "grey50")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "Δ loop score")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  geom_hline(yintercept = -0.2,
             alpha = 0.5, 
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square", linetype = "dashed") +
  coord_cartesian(ylim = c(-0.5, 0.5))
    

####
p4 <- ggplot(allLoops, aes(x = group, y = log_obsexp_diff_dTAG_DMSO, fill = group)) + 
  geom_violin(linewidth = lineThick * mmToLineUnit, lineend = "square", alpha = .4, , show.legend = FALSE) + 
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineThick * mmToLineUnit, lineend = "square",
               outlier.shape = NA,  alpha = 0.6, show.legend = FALSE) + 
  theme_classic() + 
  stat_summary(
    aes(group = group), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black", position = position_dodge(.3)
  ) +
  scale_fill_manual(values = c("grey50", "grey50")) +

  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_text(
      size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),    
    axis.text.x = element_text(
      size = fontSizeM,
      angle = 45,      # Rotate x-axis labels 45 degrees
      hjust = 1,       # Adjust horizontal justification
      vjust = 1        # Adjust vertical justification
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +labs(y = "log2(fc of obs/exp)")  +    
  geom_hline(yintercept = 0,
             alpha = 1,
             color = "black",
             size = lineThick*mmToLineUnit,
             lineend = "square") + 
  coord_cartesian(ylim = c(-2, 2))
  
width <- panelSize(2)*mmToInch
height <- panelSize(1.5)*mmToInch
fileName <- paste0("regLoopScorefromdTAG_dTAG")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(p1, p2))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(p1, p2))
dev.off()  

width <- panelSize(2)*mmToInch
height <- panelSize(1.5)*mmToInch
fileName <- paste0("regLoopScorefromdTAG_A485")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(p3, p4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(p3, p4))
dev.off()  

width <- panelSize(2)*mmToInch
height <- panelSize(1.5)*mmToInch
fileName <- paste0("regLoopScorefromdTAG_loopScore")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(p1, p3))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(p1, p3))
dev.off()  

width <- panelSize(2)*mmToInch
height <- panelSize(1.5)*mmToInch
fileName <- paste0("regLoopScorefromdTAG_log2fc")
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(plot_grid(p2, p4))
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(plot_grid(p2, p4))
dev.off()  

[3.43] Checking RAD21 peak density at group1 and group2 promoter


peak.RAD21 <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))

##########################################################
flankSize <- 5000
gene.tb <- fread(here(refDir, "mm10_GRCm38.p6_gene_sorted.bed")) %>%
  dplyr::mutate(TSS = ifelse(V4 == "+", V2, V3),
                TSSstart = TSS - flankSize,
                TSSend = TSS + flankSize) %>%
  dplyr::select(V6, V5, V1, TSSstart, TSSend)
colnames(gene.tb) <- c("ensembl_gene_id", "external_gene_name", "chr", "start", "end")


# Convert gene.tb to a GRanges object
gene_gr <- GRanges(
  seqnames = gene.tb$chr,
  ranges = IRanges(start = gene.tb$start, end = gene.tb$end),
  gene_id = gene.tb$ensembl_gene_id
)

# Count overlaps between peaks and genes
overlap_counts <- countOverlaps(gene_gr, peak.RAD21)

# Add overlap counts to the original gene.tb data
gene.tb$peak_count <- overlap_counts

###############################################################################

peakNum0 <- (gene.tb %>% dplyr::filter(peak_count == 0))$ensembl_gene_id
peakNum1 <- (gene.tb %>% dplyr::filter(peak_count == 1))$ensembl_gene_id
peakNum2 <- (gene.tb %>% dplyr::filter(peak_count == 2))$ensembl_gene_id
peakNum3 <- (gene.tb %>% dplyr::filter(peak_count == 3))$ensembl_gene_id
peakNumOver4 <- (gene.tb %>% dplyr::filter(peak_count >= 4))$ensembl_gene_id


###############################################################################
name <- "chromo_cons_annoHierarchy"

alpha <- 0.05
fcCutoff <- 0.5
diff.RNA.G1.dTAG <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha, abs(shrinked_log2FC) > fcCutoff)
diff.RNA.G1.dTAG.noFCcutoff <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::filter(padj < alpha)
geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-P", "P-E", "P-S", "P-X"))%>% 
  dplyr::mutate(distance = start2 - start1,
                peakID = paste(chrom1, start1, start2, sep = "_"))


## Dividing genes into groups
temp <- geneAnnoData %>% dplyr::select(diff_dTAG_DMSO, distance, gene) %>% 
  unnest(gene) %>% group_by(gene) %>%
  summarize(mean_diff_score = mean(diff_dTAG_DMSO),
            mean_distance = mean(distance),
            .groups = 'drop')

diff.RNA <- fread(here(refDir, "diff_G1.dTAG_G1.2i.dTAG_vs_G1.2i.DMSO.tsv")) %>%
  dplyr::select(ensembl_gene_id, log2FoldChange, shrinked_log2FC, padj, external_gene_name)

maxLog2FC = 2

temp <- left_join(temp, diff.RNA, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::mutate(flag = ifelse(gene %in% diff.RNA.G1.dTAG$ensembl_gene_id, "2DOWN", "0NO"),
                maxFlag = (abs(shrinked_log2FC) > maxLog2FC),
                log2fcMax = pmax(pmin(shrinked_log2FC, maxLog2FC), -maxLog2FC)) %>% 
  dplyr::arrange(flag) %>%
  drop_na(shrinked_log2FC)

temp <- temp %>% dplyr::mutate(
  pnOver = ifelse(gene %in% peakNum0, "peakNum0",
                  ifelse(gene %in% peakNum1, "peakNum1",
                         ifelse(gene %in% peakNum2, "peakNum2",
                                ifelse(gene %in% peakNum3, "peakNum3",
                                       ifelse(gene %in% peakNumOver4, "peakNumOver4", NA)))))) %>%
  drop_na(pnOver)

###############################################################################
# Checking percentage of genes with RAD21 peaks
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene

aaa <- temp %>% dplyr::mutate(group = case_when(
  gene %in% group1 ~ "group1",
  gene %in% group2 ~ "group2",
  TRUE ~ NA
)) %>%
  dplyr::select(group, pnOver, gene) %>%
  dplyr::filter(group %in% c("group1", "group2")) %>%
  dplyr::mutate(hasPeak = ifelse(pnOver == "peakNum0", FALSE, TRUE))

bbb <- aaa %>% dplyr::filter(group == "group1") 

sum(bbb$hasPeak)
bbb <- aaa %>% dplyr::filter(group == "group2") 
sum(bbb$hasPeak)

aaa_summary <- aaa %>%
  group_by(group, pnOver) %>%
  summarize(count = n(), .groups = "drop")

# Create the stacked barplot
aaa_summary <- aaa %>%
  group_by(group, pnOver) %>%
  summarize(count = n(), .groups = "drop") %>%
  group_by(group) %>%
  mutate(ratio = count / sum(count))

# Define the gradient colors
gradient_colors <- c("#D4D4D4", "#DCB0AF", "#E48D8A", "#EC6965", "#F44641")
# gradient_colors <- c("#D4D4D4", "#A2BBCA", "#71A2C0", "#3F89B7", "#0E71AD")

# Create the stacked barplot with gradient colors
p <- ggplot(aaa_summary, aes(x = group, y = ratio, fill = pnOver)) +
  geom_bar(stat = "identity", position = "stack",
           linewidth = lineMedium * mmToLineUnit, lineend = "square") +
  theme_classic() + labs(x = NULL , y = "Ratio") +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +
  scale_fill_manual(values = gradient_colors, 
                    guide = guide_legend(
      override.aes = list(size = 0.5), # Adjust legend key symbol size
      keywidth = 2 / 2.54, # Convert 2mm to cm
      keyheight = 2 / 2.54 # Convert 2mm to cm
    )) 

width <- panelSize(1.7)*mmToInch
height <- panelSize(1.3)*mmToInch
fileName <- paste0("rad21perc_promoter")
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  
loop score
getPvalWilcox <- function(data, group1, group2){
  distance1 <- (data %>% dplyr::filter(pnOver ==group1) )$mean_diff_score
  distance2 <- (data %>% dplyr::filter(pnOver ==group2) )$mean_diff_score
  wil <- wilcox.test(distance1, distance2)
  return(wil$p.value)
}

ps01 <- round(getPvalWilcox(temp, "peakNum0", "peakNum1"), 5)
ps12 <- round(getPvalWilcox(temp, "peakNum1", "peakNum2"), 5)
ps23 <- round(getPvalWilcox(temp, "peakNum2", "peakNum3"), 5)
ps34 <- round(getPvalWilcox(temp, "peakNum3", "peakNumOver4"), 5)
ps24 <- round(getPvalWilcox(temp, "peakNum2", "peakNumOver4"), 5)
ps14 <- round(getPvalWilcox(temp, "peakNum1", "peakNumOver4"), 5)
ps04 <- round(getPvalWilcox(temp, "peakNum0", "peakNumOver4"), 5)


p <- ggplot(temp, aes(x = pnOver, y = mean_diff_score)) + 
  geom_violin(aes(fill = pnOver), 
              color = "black",
              linewidth = lineMedium * mmToLineUnit, lineend = "square",
              show.legend = FALSE) +
  geom_boxplot(width = 0.3, color = "black",
               linewidth = lineMedium * mmToLineUnit, lineend = "square",
               outlier.shape = NA
  ) + theme_classic() + labs(x = NULL , y = "Average Δ loop score") +
  stat_summary(
    aes(group = pnOver), fun = mean,
    geom = "point", shape = 21, size = 0.5,
    fill = "black", color = "black"
  ) +
  geom_hline(yintercept = 0, linewidth = lineThick * mmToLineUnit) +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.text.x = element_text(
      angle = 45, hjust = 1, vjust = 1
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  )+
  annotate("text", x = 1, y = 0, label = paste0("ps01: ", convPvalue(ps01), "\n",
                                                "ps12: ", convPvalue(ps12), "\n",
                                                "ps23: ", convPvalue(ps23), "\n",
                                                "ps34: ", convPvalue(ps34), "\n",
                                                "ps24: ", convPvalue(ps24), "\n", 
                                                "ps14: ", convPvalue(ps14), "\n",
                                                "ps04: ", convPvalue(ps04), "\n"), 
           color = "black", hjust = 0, size = 2) +
    scale_fill_manual(values = c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C")) +
  coord_cartesian(ylim = c(-0.5, 0.1))



fileName <- paste0("diffScore_barplot_RAD21peakWithin10kb_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-38*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()
log2FC
temp <- temp %>% dplyr::mutate(absLog2FC = abs(log2FoldChange))
p <- ggplot(temp, aes(x = absLog2FC, color = pnOver)) +
scale_color_manual(values = (c("#777777", "#8B7E65", "#A28452", "#C2884D", "#F28E2C"))) +
  stat_ecdf(size = 0.4, linewidth = lineMedium * mmToLineUnit, lineend = "square" ) + # Use stat_ecdf to plot the empirical CDF
  labs(
    x = "Abs. log2(fold change)",
    y = "Cumulative Probability"
  ) + coord_cartesian(xlim = c(0, 1.5)) +
  theme_classic() + # Clean theme
  theme(
      axis.title = element_text(
        size = fontSizeM,
      family = fontType,
      color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS,
      family = fontType,
      color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000",
      size = lineThick*mmToLineUnit,
      lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.position = "none",
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
    ) + scale_y_continuous(labels = scales::number_format(accuracy = 0.1))
fileName <- paste0("log2FC_cdf_psGroup_dTAG_vs_DMSO")
width <- 33*mmToInch
height <-33*mmToInch
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

[3.44] Checking RAD21 peak density at group1 and group2 promoter


peak.RAD21 <- importPeak(here(refDir, "33250_RAD21_ab992_Bruce-4_peaks.mergePeak.bed"))
group1 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup1.tsv"))$gene
group2 <- fread(here(refDir, "geneList_dTAG_vs_DMSO_RNA_loop_binaryGroup2.tsv"))$gene


##########################################################
name <- "chromo_cons_annoHierarchy"

geneAnnoData <- loadLoopAnnoData(here(consensusDir, paste0(name, "_p-n_ensemblList.tsv")),
                                      diffCutoff = 0.2,
                                      annoList = c("P-E"))

temp1 <- geneAnnoData %>% dplyr::filter(A1 == "E") %>% dplyr::select(chrom1, start1, end1, gene)
colnames(temp1) <- c("chr", "start", "end", "gene")
temp2 <- geneAnnoData %>% dplyr::filter(A2 == "E") %>% dplyr::select(chrom2, start2, end2, gene)
colnames(temp2) <- c("chr", "start", "end", "gene")

enhAnchors <- bind_rows(temp1, temp2) %>% unnest(gene) %>%
  dplyr::mutate(
    group = case_when(
      gene %in% group1 ~ "Grp1",
      gene %in% group2 ~ "Grp2",
      TRUE ~ NA
    )
  ) %>% dplyr::filter(!is.na(group))

enh <- makeGRangesFromDataFrame(enhAnchors %>% dplyr::select(c(1, 2, 3)))

# Count overlaps between peaks and genes
overlap_counts <- countOverlaps(enh, peak.RAD21)

# Add overlap counts to the original gene.tb data
enhAnchors$peak_count <- overlap_counts

enhAnchors <- enhAnchors %>% dplyr::mutate(
  peakGroup = case_when(
    peak_count == 0 ~ "peakNum0",
    peak_count == 1 ~ "peakNum1",
    peak_count == 2 ~ "peakNum2",
    peak_count == 3 ~ "peakNum3",
    peak_count >= 4 ~ "peakNumOver4"
  )
)

aaa <- enhAnchors %>% 
  dplyr::select(group, peakGroup, gene) %>%
  dplyr::mutate(hasPeak = ifelse(peakGroup == "peakNum0", FALSE, TRUE))

bbb <- aaa %>% dplyr::filter(group == "Grp1") 
sum(bbb$hasPeak)/nrow(bbb)
bbb <- aaa %>% dplyr::filter(group == "Grp2") 
sum(bbb$hasPeak)/nrow(bbb)


aaa_summary <- aaa %>%
  group_by(group, peakGroup) %>%
  summarize(count = n(), .groups = "drop")

# Create the stacked barplot
aaa_summary <- aaa %>%
  group_by(group, peakGroup) %>%
  summarize(count = n(), .groups = "drop") %>%
  group_by(group) %>%
  mutate(ratio = count / sum(count))

# Define the gradient colors
# gradient_colors <- c("#D4D4D4", "#DCB0AF", "#E48D8A", "#EC6965", "#F44641")
gradient_colors <- c("#D4D4D4", "#A2BBCA", "#71A2C0", "#3F89B7", "#0E71AD")

# Create the stacked barplot with gradient colors
p <- ggplot(aaa_summary, aes(x = group, y = ratio, fill = peakGroup)) +
  geom_bar(stat = "identity", position = "stack",
           linewidth = lineMedium * mmToLineUnit, lineend = "square") +
  theme_classic() + labs(x = NULL , y = "Ratio") +
  theme(
    axis.title = element_text(
      size = fontSizeM, family = fontType, color = "#000000"
    ),
    axis.text = element_text(
      size = fontSizeS, family = fontType, color = "#000000"
    ),
    axis.line = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    axis.ticks = element_line(
      color = "#000000", size = lineThick * mmToLineUnit, lineend = "square"
    ),
    panel.background = element_rect(fill = "transparent"),
    legend.text = element_text(family = fontType, size = fontSizeS),
    legend.title = element_text(family = fontType, size = fontSizeS)
  ) +
  scale_fill_manual(values = gradient_colors, 
                    guide = guide_legend(
      override.aes = list(size = 0.5), # Adjust legend key symbol size
      keywidth = 2 / 2.54, # Convert 2mm to cm
      keyheight = 2 / 2.54 # Convert 2mm to cm
    )) 

width <- panelSize(1.7)*mmToInch
height <- panelSize(1.3)*mmToInch
fileName <- paste0("rad21perc_enh")
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()  

NOT CONCLUSIVE BELOW HERE


data <- fread(here(resultDir, "chromHMM", "A485_pe-pe_anchors", "overlap_enrich_100_state.txt"))
colnames(data) <- c("state", "genome", "pe-pe_A485_down", "pe-pe_A485_no", "pe-pe_A485_up")
data <- data %>% dplyr::select(-genome) %>% as.matrix()

  column_to_rownames(var = "state") %>%
  as.matrix()

library(circlize)

col_fun <- colorRamp2(c(0, 1, 10), 
                      c("blue", "white", "red"))

library(circlize)
col_fun <- colorRamp2(c(min(data), max(data)), c("white", "red"))


#fviz_nbclust(data, kmeans, method = "wss")

p <- Heatmap(
  data,
  name = "Odds Ratio",                   # Name of the heatmap legend
  cluster_columns = FALSE,            # Remove column dendrogram
  row_km = 10,                         # Define the number of k-means clusters for rows (adjust as needed)
  show_row_dend = FALSE,
  col = col_fun,
  border = TRUE
)

fileName <- paste0("anchorLOLA_dTAG_vs_DMSO_diff0.2_allLoops_extreme_regAnchorBackground_atac")
height <- 7
width <- 3.5
png(here(figDir, paste0(fileName, ".png")), res = 600, unit = "in", height = height, width = width)
print(p)
dev.off()
svglite(here(figDir, paste0(fileName, ".svg")),  height = height, width = width)
print(p)
dev.off()

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIExPQURJTkcgUkVRVUlSRU1FTlRTCiMjIFBBQ0tBR0VTCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgTElTVCBPRiBQQUNLQUdFUwpwa2dzID0gYygidGlkeXZlcnNlIiwgImhlcmUiLCAic3ZnbGl0ZSIsICJnZ3Bsb3QyIiwgImdncmVwZWwiLAogICAgICAgICAic3RyaW5nciIsICJCaW9jTWFuYWdlciIsICJSQ29sb3JCcmV3ZXIiLCAidmlyaWRpcyIsICJtYWdpY2siLAogICAgICAgICAibmxtZSIsICJmYWN0b2V4dHJhIiwgImRldnRvb2xzIiwgImJlZXByIiwgInJlbW90ZXMiLAogICAgICAgICAiY293cGxvdCIsICJkYXRhLnRhYmxlIiwgInN0cmF3ciIsICJydHJhY2tsYXllciIsICJ1dGlscyIsCiAgICAgICAgICJyZXNoYXBlMiIsICJWZW5uRGlhZ3JhbSIsImdyaWRFeHRyYSIsICJldWxlcnIiLCAic2NhbGVzIiwKICAgICAgICAgIkludGVyYWN0aW9uU2V0IiwgImdwbG90cyIsICJsb2NmZHIiLCAiZnV0dXJlIiwgImdnYmVlc3dhcm0iLCAiZ2xvc3NhcnkiKQpiaW9fcGtncyA9IGMoImJpb21hUnQiLCAiREVTZXEyIiwgIkNvbXBsZXhIZWF0bWFwIiwgImFwZWdsbSIsICJ2c24iLAogICAgICAgICAgICAgInJoZGY1IiwgIkludGVyYWN0aW9uU2V0IiwgInBsb3RnYXJkZW5lciIsICJIaUNEQ1BsdXMiLAogICAgICAgICAgICAgIkdlbm9taWNJbnRlcmFjdGlvbnMiLCAiTE9MQSIsICJBbm5vdGF0aW9uSHViIiwKICAgICAgICAgICAgICJvcmcuTW0uZWcuZGIiLCAiZW5yaWNocGxvdCIsICJET1NFIiwgImNsdXN0ZXJQcm9maWxlciIsCiAgICAgICAgICAgICAiSGlDRXhwZXJpbWVudCIsICJIaUNvb2wiLCAiSGlDb250YWN0cyIsICJIaUNvbnRhY3RzRGF0YSIsICJmb3VyRE5EYXRhIiwgIkROQVpvb0RhdGEiLAogICAgICAgICAgICAgIk1vdGlmRGIiLCAiQmlvc3RyaW5ncyIpCgojIElOU1RBTEwgUEFDS0FHRVMKIyBpbnN0YWxsLnBhY2thZ2VzKHBrZ3MpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoYmlvX3BrZ3MpCgojIElOU1RBTEwgSGlDIHJlbGF0ZWQgcGFja2FnZXMKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicm9iaW53ZWlkZS9HRU5PVkEiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigidGhvbWFzcDg1L3NjaWNvIikKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInBzeXRlYWNoci9pbnRyb2RhdGF2aXoiKQoKIyBMT0FEIFBBQ0tBR0VTCmxhcHBseShwa2dzLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCmxhcHBseShiaW9fcGtncywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpyZXF1aXJlKEdFTk9WQSkKcmVxdWlyZShzY2ljbykKcmVxdWlyZShpbnRyb2RhdGF2aXopCgojIENMRUFOSU5HCnJtKHBrZ3MsIGJpb19wa2dzKQoKb3B0aW9ucyhzY2lwZW49OTk5KQoKCgpgYGAKIyMgRU5TRU1CTApgYGB7cn0KIyBFTlNFTUJMIERBVEFCQVNFCiMgdjEwMiBpcyBmb3IgdGhlIGxhdGVzdCBtbTEwIHZlcnNpb24KIyBlbnNlbWJsLnYxMDIgPC0gdXNlTWFydChob3N0ID0gImh0dHBzOi8vbm92MjAyMC5hcmNoaXZlLmVuc2VtYmwub3JnIiwKIyAgICAgICAgICAgICAgICAgICAgICAgIGJpb21hcnQgPSAiRU5TRU1CTF9NQVJUX0VOU0VNQkwiLAojICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldCA9ICJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIikKYGBgCiMjIENPTE9SIFBBTEVUVEUKYGBge3J9CnBhbGV0dGVfMSA9IGxpc3QocmVkID0gIiNFOTAwMkQiLAogICAgICAgICAgICAgICAgIGFtYmVyID0gIiNGRkFBMDAiLAogICAgICAgICAgICAgICAgIGdyZWVuID0gIiMwMEIwMDAiKQpwYWxldHRlXzIgPSBsaXN0KHJlZCA9ICIjRkYxRjVCIiwKICAgICAgICAgICAgICAgICBncmVlbiA9ICIjMDBDRDZDIiwKICAgICAgICAgICAgICAgICBibHVlID0gIiMwMDlBREUiLAogICAgICAgICAgICAgICAgIHB1cnBsZSA9ICIjQUY1OEJBIiwKICAgICAgICAgICAgICAgICB5ZWxsb3cgPSAiI0ZGQzYxRSIsCiAgICAgICAgICAgICAgICAgb3JhbmdlID0gIiNGMjg1MjIiLAogICAgICAgICAgICAgICAgIGdyZXkgPSAiI0EwQjFCQSIsCiAgICAgICAgICAgICAgICAgYnJvd24gPSAiI0E2NzYxRCIpCnBhbGV0dGVfMyA9IGxpc3QoZ3JleTEgPSAiI2EwYjFiYSIsCiAgICAgICAgICAgICAgICAgZ3JleTIgPSAiI2M1ZDBkNSIsCiAgICAgICAgICAgICAgICAgZ3JleTMgPSAiI2VjZWZmMSIpCgpjb2xvckxpc3RMb29wIDwtICBjKHBhbGV0dGVfM1tbImdyZXkzIl1dLCBwYWxldHRlXzNbWyJncmV5MiJdXSwgcGFsZXR0ZV8zW1siZ3JleTEiXV0sCiAgICAgICAgICAgICAgICAgICAgICIjQzVFMUVGIiwgIiM2Q0IwRDYiLCAiIzIyNkU5QyIsCiAgICAgICAgICAgICAgICAgICAgICIjMDY1OTJBIiwgCiAgICAgICAgICAgICAgICAgICAgICIjRkVEOTc2IiwgIiNGRDhEM0MiLCAiI0UzMUExQyIpCmNvbG9yTGlzdFByb21vdGVyIDwtIGMocGFsZXR0ZV8zW1siZ3JleTMiXV0sIiNFODg1ODciLCAiI0UzMUExQyIpCmNvbG9yTGlzdEVuaGFuY2VyIDwtIGMocGFsZXR0ZV8zW1siZ3JleTMiXV0sIiM4N0FGQzciLCAiIzIyNkU5QyIpCmNvbG9yTGlzdFN0cnVjdHVyZSA8LSBjKHBhbGV0dGVfM1tbImdyZXkzIl1dLCBwYWxldHRlXzNbWyJncmV5MiJdXSwgcGFsZXR0ZV8zW1siZ3JleTEiXV0pCmBgYAoKIyMgRElSIExJU1QKYGBge3J9CiMgCiMgbG9vcERpciA8LSBoZXJlKCIuLi8uLiIsICJyZXN1bHQiLCAibG9vcCIsICJjaHJvbW9fZGV0ZWN0IikKIyBzY29yZURpciA8LSBoZXJlKCIuLi8uLiIsICJyZXN1bHQiLCAibG9vcCIsICJjaHJvbW9fcXVhbnRpZnkiKQojIGNvbnNlbnN1c0RpciA8LSBoZXJlKCIuLi8uLiIsICJyZXN1bHQiLCAibG9vcCIsICJjb25zZW5zdXMiKQojIGZpZ0RpciA8LSBoZXJlKCIuLi8uLiIsICJmaWd1cmUiLCAibG9vcCIpCiMgcmVmRGlyIDwtIGhlcmUoIi4uLy4uIiwgInJlZmVyZW5jZSIpCgpgYGAKIyMgRklHVVJFIFBBUkFNRVRFUlMKYGBge3J9CmxpYnJhcnkoY29sb3JzcGFjZSkKCmZvbnRUeXBlIDwtICJIZWx2ZXRpY2EiCgpmb250U2l6ZUwgPC0gMTAgIyBwdApmb250U2l6ZU0gPC0gOApmb250U2l6ZVMgPC0gNgoKbGluZVRoaWNrIDwtIDAuNzUgIyBwdApsaW5lTWVkaXVtIDwtIDAuNQpsaW5lVGhpbiA8LSAwLjI1CgpwYW5lbFVuaXQgPC0gMzAgIyBtbQpwYW5lbE1hcmdpbiA8LSAxLjUKCm1tVG9JbmNoIDwtIDAuMDM5MzcwMDc4NzQKbW1Ub0xpbmVVbml0IDwtIDEvMi4xMwptbVRvTGluZVBsb3RnYXJkZW4gPC0gMS8wLjc1CnB0VG9NTSA8LSAxLzIuODQ1CgoKc3Ryb25nX3JlZCA8LSAiI0NCMzMzQSIKc3Ryb25nX2JsdWUgPC0gIiM0ODUxQTAiCndlYWtfcmVkIDwtIGxpZ2h0ZW4oc3Ryb25nX3JlZCwgYW1vdW50ID0gMC40KSAgICMgRkY3RDgxCndlYWtfYmx1ZSA8LSBsaWdodGVuKHN0cm9uZ19ibHVlLCBhbW91bnQgPSAwLjQpICMgOEE5MURECm5vX2dyZXkgPC0gIiNBOEE4QTgiCgpzdHJvbmdfdGVlbCA8LSAiIzA4OTJBNSIKc3Ryb25nX2dyZWVuIDwtICIjMjNDRTZCIiAjIEE0ODUKc3Ryb25nX2RhcmtncmVlbiA8LSAiIzA1NEEyOSIKc3Ryb25nX3llbGxvdyA8LSAiI0ZGQkE0OSIKc3Ryb25nX29yYW5nZSA8LSAiI0YxOEYwMSIgIyBkVEFHCnN0cm9uZ19saWdodHB1cnBsZSA8LSAiI0JEOTNEOCIKc3Ryb25nX3B1cnBsZSA8LSAiIzlFMzNDQiIgIyBFcGkKCnBhbmVsU2l6ZSA8LSBmdW5jdGlvbihudW0sIHVuaXQgPSBwYW5lbFVuaXQsIG1hcmdpbiA9IHBhbmVsTWFyZ2luKXsKICByZXR1cm4obnVtKnVuaXQgLSAyKm1hcmdpbikKfQoKYGBgCiMjIEZVTkNUSU9OUwpgYGB7cn0KaW1wb3J0QmVkcGUgPSBmdW5jdGlvbihiZWRwZSl7CiAgYTEgPSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZGF0YS5mcmFtZSgKICAgIGNociA9IGJlZHBlJFYxLAogICAgc3RhcnQgPSBiZWRwZSRWMiArMSwKICAgIGVuZCA9IGJlZHBlJFYzKSkKICBhMiA9IG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShkYXRhLmZyYW1lKAogICAgY2hyID0gYmVkcGUkVjQsCiAgICBzdGFydCA9IGJlZHBlJFY1ICsxLAogICAgZW5kID0gYmVkcGUkVjYpKQogIEdJbnRlcmFjdGlvbnMoYTEsIGEyKQp9CgpnZXRfZGVuc2l0eSA8LSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICBkZW5zIDwtIE1BU1M6OmtkZTJkKHgsIHksIC4uLikKICBpeCA8LSBmaW5kSW50ZXJ2YWwoeCwgZGVucyR4KQogIGl5IDwtIGZpbmRJbnRlcnZhbCh5LCBkZW5zJHkpCiAgaWkgPC0gY2JpbmQoaXgsIGl5KQogIHJldHVybihkZW5zJHpbaWldKQp9CmxhYmVsX2tiX21iIDwtIGZ1bmN0aW9uKHgpIHsKICBpZmVsc2UoeCA+PSAxMDAwMDAwLCBwYXN0ZTAoeCAvIDEwMDAwMDAsICJNYiIpLCBwYXN0ZTAoeCAvIDEwMDAsICJrYiIpKQp9CgppbXBvcnRQZWFrID0gZnVuY3Rpb24oZmlsZU5hbWUpewogIGRmID0gZnJlYWQoZmlsZU5hbWUpCiAgZ3IgPSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZGF0YS5mcmFtZSgKICAgIGNociA9IGRmJFYxLCBzdGFydCA9IGRmJFYyLCBlbmQgPSBkZiRWMwogICkpCn0KYGBgCgoKCiMjIyMgQ29tcGFyaW5nIEcxIHZzIEFzeW5jIGZvciBjb25zZW5zdXMgbG9vcHMKIyMjIyMgQWxsIGxvb3BzCmBgYHtyfQpkaWZmQ3V0b2ZmID0gMC4yCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZS50c3YiKSkKCnRlbXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZV9hc3luYy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChpZCwgVVQsIEFJRCkKCnNjb3JlLnRiIDwtIGRhdGEgJT4lIGRwbHlyOjpmdWxsX2pvaW4odGVtcCwgYnkgPSBjKCJpZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRpZmZfRzEgPSBkVEFHIC0gRE1TTywKICAgICAgICAgICAgICAgICAgZGlmZl9hc3luYyA9IEFJRCAtIFVUKQoKCiMjIyBQMS4gVVQgdnMgQUlECnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkVVQsIHNjb3JlLnRiJEFJRCwgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRVVCwgc2NvcmUudGIkQUlEKQpwMSA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gVVQsIHkgPSBBSUQsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKHBhc3RlMCgiQ29uc2Vuc3VzIGxvb3Agc2NvcmUiKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKIyMjIFAxLiBETVNPIHZzIGRUQUcKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRETVNPLCBzY29yZS50YiRkVEFHLCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJGRUQUcpCnAyIDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBETVNPLCB5ID0gZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMC41LCAxKSArIHlsaW0oLTAuNSwgMSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgoKIyMjIFAzLiBETVNPIHZzIEE0ODUKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRETVNPLCBzY29yZS50YiRBNDg1LCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJEE0ODUpCnAzIDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBETVNPLCB5ID0gQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMC41LCAxKSArIHlsaW0oLTAuNSwgMSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgojIyMgUDMuIERNU08gdnMgVVQKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRETVNPLCBzY29yZS50YiRVVCwgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRETVNPLCBzY29yZS50YiRVVCkKcDQgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IERNU08sIHkgPSBVVCwgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMC41LCAxKSArIHlsaW0oLTAuNSwgMSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgoKIyMjIFAzLiBkVEFHIHZzIEFJRApzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJGRUQUcsIHNjb3JlLnRiJEFJRCwgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRkVEFHLCBzY29yZS50YiRBSUQpCnA1IDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBkVEFHLCB5ID0gQUlELCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCiMjIyBQMy4gZGlmZgpzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJGRpZmZfRzEsIHNjb3JlLnRiJGRpZmZfYXN5bmMsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkZGlmZl9HMSwgc2NvcmUudGIkZGlmZl9hc3luYykKcDYgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IGRpZmZfRzEsIHkgPSBkaWZmX2FzeW5jLCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0xLCAwLjUpICsgeWxpbSgtMSwgMC41KSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCgpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMCgiY29uc2Vuc3VzX3Njb3JlX3NjYXR0ZXJwbG90X3B1MTAwcHoxMDBfRzF2c0FzeW5jLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNSoyLjUsIGhlaWdodCA9IDIuNSoyLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHA0LCBwNSwgcDYsIGFsaWduID0gImgiLCBuY29sID0gMykpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoImNvbnNlbnN1c19zY29yZV9zY2F0dGVycGxvdF9wdTEwMHB6MTAwX0cxdnNBc3luYy5zdmciKSksIHdpZHRoID0gNSoyLjUsIGhlaWdodCA9IDIuNSoyLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHA0LCBwNSwgcDYsIGFsaWduID0gImgiLCBuY29sID0gMykpCmRldi5vZmYoKQoKCmBgYAojIyMjIyByZWcgbG9vcHMKYGBge3J9CnRlbXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpICU+JQogIGRwbHlyOjptdXRhdGUocmVzID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIHJlcywgVjIsIFY1LCBzZXAgPSAiXyIpKQpyZWdJRCA8LSB0ZW1wJGlkCgpkaWZmQ3V0b2ZmID0gMC4yCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZS50c3YiKSkKCnRlbXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZV9hc3luYy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChpZCwgVVQsIEFJRCkKCnNjb3JlLnRiIDwtIGRhdGEgJT4lIGRwbHlyOjpmdWxsX2pvaW4odGVtcCwgYnkgPSBjKCJpZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRpZmZfRzEgPSBkVEFHIC0gRE1TTywKICAgICAgICAgICAgICAgICAgZGlmZl9hc3luYyA9IEFJRCAtIFVUKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgcmVnSUQpCgoKIyMjIFAxLiBVVCB2cyBBSUQKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRVVCwgc2NvcmUudGIkQUlELCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJFVULCBzY29yZS50YiRBSUQpCnAxIDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBVVCwgeSA9IEFJRCwgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMC41LCAxKSArIHlsaW0oLTAuNSwgMSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgojIyMgUDEuIERNU08gdnMgZFRBRwpzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJGRUQUcsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkRE1TTywgc2NvcmUudGIkZFRBRykKcDIgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IERNU08sIHkgPSBkVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCgojIyMgUDMuIERNU08gdnMgQTQ4NQpzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJEE0ODUsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkRE1TTywgc2NvcmUudGIkQTQ4NSkKcDMgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IERNU08sIHkgPSBBNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCiMjIyBQMy4gRE1TTyB2cyBVVApzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJFVULCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJERNU08sIHNjb3JlLnRiJFVUKQpwNCA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gRE1TTywgeSA9IFVULCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCgojIyMgUDMuIGRUQUcgdnMgQUlECnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkZFRBRywgc2NvcmUudGIkQUlELCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJGRUQUcsIHNjb3JlLnRiJEFJRCkKcDUgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IGRUQUcsIHkgPSBBSUQsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKHBhc3RlMCgiQ29uc2Vuc3VzIGxvb3Agc2NvcmUiKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKIyMjIFAzLiBkaWZmCnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkZGlmZl9HMSwgc2NvcmUudGIkZGlmZl9hc3luYywgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRkaWZmX0cxLCBzY29yZS50YiRkaWZmX2FzeW5jKQpwNiA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gZGlmZl9HMSwgeSA9IGRpZmZfYXN5bmMsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTEsIDAuNSkgKyB5bGltKC0xLCAwLjUpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTEsIHkgPSAwLjUsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgoKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoImNvbnNlbnN1c19zY29yZV9zY2F0dGVycGxvdF9wdTEwMHB6MTAwX0cxdnNBc3luY19yZWcucG5nIikpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSA1KjIuNSwgaGVpZ2h0ID0gMi41KjIuNSkKcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgcDQsIHA1LCBwNiwgYWxpZ24gPSAiaCIsIG5jb2wgPSAzKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMCgiY29uc2Vuc3VzX3Njb3JlX3NjYXR0ZXJwbG90X3B1MTAwcHoxMDBfRzF2c0FzeW5jX3JlZy5zdmciKSksIHdpZHRoID0gNSoyLjUsIGhlaWdodCA9IDIuNSoyLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHA0LCBwNSwgcDYsIGFsaWduID0gImgiLCBuY29sID0gMykpCmRldi5vZmYoKQoKCiMjIyMjIyMjIyMgU2F2aW5nIEFzeW5jIGFuZCBHMSBzcGVjaWZpYyByZWd1bGF0b3J5IGxvb3AKZGlmZkN1dG9mZiA8LSAwLjIKdGVtcCA8LSBzY29yZS50YiAlPiUgZHBseXI6OmZpbHRlcihkaWZmX0cxID49IC1kaWZmQ3V0b2ZmLCBkaWZmX2FzeW5jID49IC1kaWZmQ3V0b2ZmKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcSgxLCA3KSkKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9HMXZzQXN5bmNfYm90aFJldGFpbmVkLmJlZHBlIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQoKdGVtcCA8LSBzY29yZS50YiAlPiUgZHBseXI6OmZpbHRlcihkaWZmX0cxID49IC1kaWZmQ3V0b2ZmLCBkaWZmX2FzeW5jIDwgLWRpZmZDdXRvZmYpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2VxKDEsIDcpKQpmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0cxdnNBc3luY19Bc3luY1NwZWNpZmljUGVydC5iZWRwZSIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKCnRlbXAgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZGlmZl9HMSA8IC1kaWZmQ3V0b2ZmLCBkaWZmX2FzeW5jID49IC1kaWZmQ3V0b2ZmKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcSgxLCA3KSkKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9HMXZzQXN5bmNfRzFTcGVjaWZpY1BlcnQuYmVkcGUiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCgp0ZW1wIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6ZmlsdGVyKGRpZmZfRzEgPCAtZGlmZkN1dG9mZiwgZGlmZl9hc3luYyA8IC1kaWZmQ3V0b2ZmKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcSgxLCA3KSkKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9HMXZzQXN5bmNfYm90aFBlcnQuYmVkcGUiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCmBgYAoKIyMjIyMgc3RyIGxvb3BzCmBgYHtyfQp0ZW1wIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmUuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShyZXMgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgcmVzLCBWMiwgVjUsIHNlcCA9ICJfIikpCnJlZ0lEIDwtIHRlbXAkaWQKCmRpZmZDdXRvZmYgPSAwLjIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX3Njb3JlLnRzdiIpKQoKdGVtcCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX3Njb3JlX2FzeW5jLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGlkLCBVVCwgQUlEKQoKc2NvcmUudGIgPC0gZGF0YSAlPiUgZHBseXI6OmZ1bGxfam9pbih0ZW1wLCBieSA9IGMoImlkIikpICU+JQogIGRwbHlyOjptdXRhdGUoZGlmZl9HMSA9IGRUQUcgLSBETVNPLAogICAgICAgICAgICAgICAgICBkaWZmX2FzeW5jID0gQUlEIC0gVVQpICU+JQogIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSByZWdJRCkKCgojIyMgUDEuIFVUIHZzIEFJRApzY29yZS50YiRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHNjb3JlLnRiJFVULCBzY29yZS50YiRBSUQsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkVVQsIHNjb3JlLnRiJEFJRCkKcDEgPC0gZ2dwbG90KHNjb3JlLnRiLCBhZXMoeCA9IFVULCB5ID0gQUlELCBjb2xvciA9IGRlbnNpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkNvbnNlbnN1cyBsb29wIHNjb3JlIikpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCiMjIyBQMS4gRE1TTyB2cyBkVEFHCnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkRE1TTywgc2NvcmUudGIkZFRBRywgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRETVNPLCBzY29yZS50YiRkVEFHKQpwMiA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gRE1TTywgeSA9IGRUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKHBhc3RlMCgiQ29uc2Vuc3VzIGxvb3Agc2NvcmUiKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKCiMjIyBQMy4gRE1TTyB2cyBBNDg1CnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkRE1TTywgc2NvcmUudGIkQTQ4NSwgbiA9IDEwMCkKc2NvcmUudGIgPC0gc2NvcmUudGIgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmNvcnJlbGF0aW9uIDwtIGNvcihzY29yZS50YiRETVNPLCBzY29yZS50YiRBNDg1KQpwMyA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gRE1TTywgeSA9IEE0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKHBhc3RlMCgiQ29uc2Vuc3VzIGxvb3Agc2NvcmUiKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKIyMjIFAzLiBETVNPIHZzIFVUCnNjb3JlLnRiJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoc2NvcmUudGIkRE1TTywgc2NvcmUudGIkVVQsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkRE1TTywgc2NvcmUudGIkVVQpCnA0IDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBETVNPLCB5ID0gVVQsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsKICBjb29yZF9maXhlZCgpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbCA9ICJncmV5NTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKHBhc3RlMCgiQ29uc2Vuc3VzIGxvb3Agc2NvcmUiKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKCiMjIyBQMy4gZFRBRyB2cyBBSUQKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRkVEFHLCBzY29yZS50YiRBSUQsIG4gPSAxMDApCnNjb3JlLnRiIDwtIHNjb3JlLnRiICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpjb3JyZWxhdGlvbiA8LSBjb3Ioc2NvcmUudGIkZFRBRywgc2NvcmUudGIkQUlEKQpwNSA8LSBnZ3Bsb3Qoc2NvcmUudGIsIGFlcyh4ID0gZFRBRywgeSA9IEFJRCwgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMC41LCAxKSArIHlsaW0oLTAuNSwgMSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgojIyMgUDMuIGRpZmYKc2NvcmUudGIkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShzY29yZS50YiRkaWZmX0cxLCBzY29yZS50YiRkaWZmX2FzeW5jLCBuID0gMTAwKQpzY29yZS50YiA8LSBzY29yZS50YiAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKY29ycmVsYXRpb24gPC0gY29yKHNjb3JlLnRiJGRpZmZfRzEsIHNjb3JlLnRiJGRpZmZfYXN5bmMpCnA2IDwtIGdncGxvdChzY29yZS50YiwgYWVzKHggPSBkaWZmX0cxLCB5ID0gZGlmZl9hc3luYywgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgeGxpbSgtMSwgMC41KSArIHlsaW0oLTEsIDAuNSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKCJDb25zZW5zdXMgbG9vcCBzY29yZSIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTEsIHkgPSAwLjUsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgoKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoImNvbnNlbnN1c19zY29yZV9zY2F0dGVycGxvdF9wdTEwMHB6MTAwX0cxdnNBc3luY19zdHIucG5nIikpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSA1KjIuNSwgaGVpZ2h0ID0gMi41KjIuNSkKcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgcDQsIHA1LCBwNiwgYWxpZ24gPSAiaCIsIG5jb2wgPSAzKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMCgiY29uc2Vuc3VzX3Njb3JlX3NjYXR0ZXJwbG90X3B1MTAwcHoxMDBfRzF2c0FzeW5jX3N0ci5zdmciKSksIHdpZHRoID0gNSoyLjUsIGhlaWdodCA9IDIuNSoyLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHA0LCBwNSwgcDYsIGFsaWduID0gImgiLCBuY29sID0gMykpCmRldi5vZmYoKQoKCmBgYAojIyMjIENvbXBhcmluZyBsb29wcyBjYWxsZWQgZnJvbSBBc3luYwpgYGB7cn0KIyBJbXBvcnRpbmcgbG9vcHMuIEZvciBtYWtlIGNvbXBhcmlzb24gZWFzaWVyLCAyNSBrYgpiaW5TaXplID0gMjUqMTAwMAp0ZW1wIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVGppYW5fY2hyb21vc2lnaHRfbG9vcC5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGNlbnRlcjEgPSAwLjUqKFYyICsgVjMpLAogICAgICAgICAgICAgICAgY2VudGVyMiA9IDAuNSooVjUgKyBWNiksCiAgICAgICAgICAgICAgICBzdGFydDEgPSBjZW50ZXIxIC0gMC41KmJpblNpemUsCiAgICAgICAgICAgICAgICBlbmQxID0gY2VudGVyMSArIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgc3RhcnQyID0gY2VudGVyMiAtIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgZW5kMiA9IGNlbnRlcjIgKyAwLjUqYmluU2l6ZSkgJT4lCiAgZHBseXI6OnNlbGVjdChWMSwgc3RhcnQxLCBlbmQxLCBWNCwgc3RhcnQyLCBlbmQyKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJWMSIsICJWMiIsICJWMyIsICJWNCIsICJWNSIsICJWNiIpCmxvb3AuYXN5bmMgPC0gaW1wb3J0QmVkcGUodGVtcCkKCgpiaW5TaXplID0gMjUqMTAwMAp0ZW1wIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnMuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIxID0gMC41KihWMiArIFYzKSwKICAgICAgICAgICAgICAgIGNlbnRlcjIgPSAwLjUqKFY1ICsgVjYpLAogICAgICAgICAgICAgICAgc3RhcnQxID0gY2VudGVyMSAtIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgZW5kMSA9IGNlbnRlcjEgKyAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIHN0YXJ0MiA9IGNlbnRlcjIgLSAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIGVuZDIgPSBjZW50ZXIyICsgMC41KmJpblNpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIHN0YXJ0MSwgZW5kMSwgVjQsIHN0YXJ0MiwgZW5kMikKY29sbmFtZXModGVtcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQpsb29wLkcxIDwtIGltcG9ydEJlZHBlKHRlbXApCgoKIyBDaGVjayBvdmVybGFwCm92ZXJsYXAgPC0gZmluZE92ZXJsYXBzKGxvb3AuYXN5bmMsIGxvb3AuRzEpCgoKbi5hc3luYyA8LSBucm93KGFzX3RpYmJsZShsb29wLmFzeW5jKSkKbi5HMSA8LSBucm93KGFzX3RpYmJsZShsb29wLkcxKSkKbi5hc3luYy5vdmVybGFwIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXApKSkKbi5HMS5vdmVybGFwIDwtIGxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcCkpKQoKcGxvdChldWxlcihjKCJBc3luYyIgPSBuLmFzeW5jIC0gbi5hc3luYy5vdmVybGFwLAogICAgICAgICAgICAgIkFzeW5jJkcxIiA9IG4uYXN5bmMub3ZlcmxhcCwKICAgICAgICAgICAgICJHMSIgPSAxKSksIHF1YW50aXRpZXMgPSBUUlVFKQoKCnBsb3QoZXVsZXIoYygiQXN5bmMiID0xLAogICAgICAgICAgICAgIkFzeW5jJkcxIiA9IG4uRzEub3ZlcmxhcCwKICAgICAgICAgICAgICJHMSIgPSBuLkcxIC0gbi5HMS5vdmVybGFwKSksIHF1YW50aXRpZXMgPSBUUlVFKQoKCgoKIyBJbXBvcnRpbmcgbG9vcHMuIEZvciBtYWtlIGNvbXBhcmlzb24gZWFzaWVyLCAyNSBrYgpiaW5TaXplID0gMjUqMTAwMAp0ZW1wLnBwIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVGppYW5fY2hyb21vc2lnaHRfbG9vcF9QLVAuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIxID0gMC41KihWMiArIFYzKSwKICAgICAgICAgICAgICAgIGNlbnRlcjIgPSAwLjUqKFY1ICsgVjYpLAogICAgICAgICAgICAgICAgc3RhcnQxID0gY2VudGVyMSAtIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgZW5kMSA9IGNlbnRlcjEgKyAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIHN0YXJ0MiA9IGNlbnRlcjIgLSAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIGVuZDIgPSBjZW50ZXIyICsgMC41KmJpblNpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIHN0YXJ0MSwgZW5kMSwgVjQsIHN0YXJ0MiwgZW5kMikKY29sbmFtZXModGVtcC5wcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQpiaW5TaXplID0gMjUqMTAwMAp0ZW1wLmVwIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVGppYW5fY2hyb21vc2lnaHRfbG9vcF9FLVAuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIxID0gMC41KihWMiArIFYzKSwKICAgICAgICAgICAgICAgIGNlbnRlcjIgPSAwLjUqKFY1ICsgVjYpLAogICAgICAgICAgICAgICAgc3RhcnQxID0gY2VudGVyMSAtIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgZW5kMSA9IGNlbnRlcjEgKyAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIHN0YXJ0MiA9IGNlbnRlcjIgLSAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIGVuZDIgPSBjZW50ZXIyICsgMC41KmJpblNpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIHN0YXJ0MSwgZW5kMSwgVjQsIHN0YXJ0MiwgZW5kMikKY29sbmFtZXModGVtcC5lcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQp0ZW1wIDwtIGJpbmRfcm93cyh0ZW1wLnBwLCB0ZW1wLmVwKQpsb29wLmFzeW5jIDwtIGltcG9ydEJlZHBlKHRlbXApCgoKYmluU2l6ZSA9IDI1KjEwMDAKdGVtcCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIxID0gMC41KihWMiArIFYzKSwKICAgICAgICAgICAgICAgIGNlbnRlcjIgPSAwLjUqKFY1ICsgVjYpLAogICAgICAgICAgICAgICAgc3RhcnQxID0gY2VudGVyMSAtIDAuNSpiaW5TaXplLAogICAgICAgICAgICAgICAgZW5kMSA9IGNlbnRlcjEgKyAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIHN0YXJ0MiA9IGNlbnRlcjIgLSAwLjUqYmluU2l6ZSwKICAgICAgICAgICAgICAgIGVuZDIgPSBjZW50ZXIyICsgMC41KmJpblNpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIHN0YXJ0MSwgZW5kMSwgVjQsIHN0YXJ0MiwgZW5kMikKY29sbmFtZXModGVtcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQpsb29wLkcxIDwtIGltcG9ydEJlZHBlKHRlbXApCgoKIyBDaGVjayBvdmVybGFwCm92ZXJsYXAgPC0gZmluZE92ZXJsYXBzKGxvb3AuYXN5bmMsIGxvb3AuRzEpCgoKbi5hc3luYyA8LSBucm93KGFzX3RpYmJsZShsb29wLmFzeW5jKSkKbi5HMSA8LSBucm93KGFzX3RpYmJsZShsb29wLkcxKSkKbi5hc3luYy5vdmVybGFwIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXApKSkKbi5HMS5vdmVybGFwIDwtIGxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcCkpKQoKcGxvdChldWxlcihjKCJBc3luYyIgPSBuLmFzeW5jIC0gbi5hc3luYy5vdmVybGFwLAogICAgICAgICAgICAgIkFzeW5jJkcxIiA9IG4uYXN5bmMub3ZlcmxhcCwKICAgICAgICAgICAgICJHMSIgPSAxKSksIHF1YW50aXRpZXMgPSBUUlVFKQoKCnBsb3QoZXVsZXIoYygiQXN5bmMiID0wLjEsCiAgICAgICAgICAgICAiQXN5bmMmRzEiID0gbi5HMS5vdmVybGFwLAogICAgICAgICAgICAgIkcxIiA9IG4uRzEgLSBuLkcxLm92ZXJsYXApKSwgcXVhbnRpdGllcyA9IFRSVUUpCgpgYGAKCgojIyMgWzIuNV0gQ29uc2Vuc3VzIGxvb3AgYW5ub3RhdGlvbgpgYGB7cn0KIyMjIyBJbXBvcnRpbmcgQ2hJUC1leG8gcGVha3MKcmVmRGlyIDwtIGhlcmUoIi4uLy4uIiwgInJlZmVyZW5jZSIpCnBlYWsuSDNLMjdhYyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCnBlYWsuSDNLNG1lMyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTVfSDNLNG1lM18wNC03NDVfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBlYWsuQ1RDRiA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBlYWsuUkFEMjEgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQpwZWFrLldoeXRlLlNFIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJzdXBlckVuaGFuY2VyX1doeXRlX0VTQ19tbTEwLmJlZCIpKQpwZWFrLkR5bGFuLlNFIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJzdXBlckVuaGFuY2VyX0R5bGFuX0VTQy5iZWQiKSkKYGBgCiMjIyMgRnVuY3Rpb25zCmBgYHtyfQpjcmVhdGVMb29wQW5ub3RhdGlvbiA8LSBmdW5jdGlvbihiZWRwZS5sb29wLmFubm8sIG5hbWUsIGZpZ0Rpciwgb3V0RGlyLCBjb2xvckxpc3QpewogIHRlbXAgPSBiZWRwZS5sb29wLmFubm8gJT4lCiAgICBkcGx5cjo6bXV0YXRlKHNhbXBsZSA9IG5hbWUpCiAgCiAgbnVtID0gbnJvdyh0ZW1wKQogIHA3ID0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2FtcGxlLCBmaWxsID0gQW5ubzIpKSArCiAgICBnZW9tX2Jhcihjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlMChudW0sICIgbG9vcHMiKSwKICAgICAgICAgeCA9ICIiLCB5ID0gIkNvdW50cyIpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYV9mb3JtYXQoKSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICBhc3BlY3QucmF0aW8gPSA1LAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gID0gInZlcnRpY2FsIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JMaXN0KQogIAogIHdpZHRoID0gMwogIGhlaWdodCA9IDUKICBzdmdsaXRlKGhlcmUoZmlnRGlyLAogICAgICAgICAgICAgICBwYXN0ZTAoImxvb3BDbGFzc2lmeV8iLCBuYW1lLCAiLnN2ZyIpKSwKICAgICAgICAgIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9IGhlaWdodCkKICBwbG90KHA3KQogIGludmlzaWJsZShkZXYub2ZmKCkpCiAgcG5nKGhlcmUoZmlnRGlyLAogICAgICAgICAgIHBhc3RlMCgibG9vcENsYXNzaWZ5XyIsIG5hbWUsICIucG5nIikpLAogICAgICB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iKQogIHBsb3QocDcpCiAgaW52aXNpYmxlKGRldi5vZmYoKSkKfQoKCmFubm90YXRlTG9vcFJlbGF4ZWRUU1MgPC0gZnVuY3Rpb24oYmVkcGUuYW5ubyl7CiAgdGVtcCA9IGJlZHBlLmFubm8gJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBBMSA9IGlmX2Vsc2UoKEExX0gzSzRtZTNUU1MpLCAiUCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZSgoQTFfSDNLMjdhYyksICJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSgoQTFfQ1RDRnxBMV9SQUQyMSksICJTIiwgIlgiKSkpLAogICAgICBBMiA9IGlmX2Vsc2UoKEEyX0gzSzRtZTNUU1MpLCAiUCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZSgoQTJfSDNLMjdhYyksICJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSgoQTJfQ1RDRnxBMl9SQUQyMSksICJTIiwgIlgiKSkpCiAgICApCiAgdGVtcCA9IHRlbXAgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEFubm8gPSBwYXN0ZTAoQTEsICItIiwgQTIpLAogICAgICAgICAgICAgICAgICBBbm5vMiA9IGlmX2Vsc2UoQW5ubyA9PSAiRS1QIiwgIlAtRSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShBbm5vID09ICJTLVAiLCAiUC1TIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShBbm5vID09ICJYLVAiLCAiUC1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKEFubm8gPT0gIlMtRSIsICJFLVMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShBbm5vID09ICJYLUUiLCAiRS1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShBbm5vID09ICJYLVMiLCAiUy1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbm5vKSkpKSkpLAogICAgKQogIAogIHRlbXAkQW5ubzIgPSBmYWN0b3IodGVtcCRBbm5vMiwgbGV2ZWwgPSBjKCJYLVgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTLVgiLCAiUy1TIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRS1YIiwiRS1TIiwiRS1FIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUC1FIiwiUC1YIiwgIlAtUyIsICJQLVAiKSkKICAKICAjIENoZWNraW5nIHRoZSBwcmVjZW5zZSBvZiBzdXBlciBlbmhhbmNlcgogIHRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OnJvd3dpc2UoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoQW5ub1NFID0gaWZlbHNlKEExX1doeXRlLlNFIHwgQTJfV2h5dGUuU0UsICJTRSIsICJOTyIpKQogIHRlbXAkQW5ub1NFIDwtIGZhY3Rvcih0ZW1wJEFubm9TRSwgbGV2ZWwgPSBjKCJTRSIsICJOTyIpKQogIAogIHJldHVybih0ZW1wKQp9Cgphbm5vdGF0ZUxvb3BQcm9tb3RlclRTUyA8LSBmdW5jdGlvbihiZWRwZS5hbm5vKXsKICB0ZW1wID0gYmVkcGUuYW5ubyAlPiUgZHBseXI6OnJvd3dpc2UoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIEExID0gaWZfZWxzZSgoQTFfSDNLNG1lM1RTUyksICJQIiwgIk4iKSwKICAgICAgQTIgPSBpZl9lbHNlKChBMl9IM0s0bWUzVFNTKSwgIlAiLCAiTiIpCiAgICApCiAgdGVtcCA9IHRlbXAgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEFubm8gPSBwYXN0ZTAoQTEsICItIiwgQTIpLAogICAgICAgICAgICAgICAgICBBbm5vMiA9IGlmX2Vsc2UoQW5ubyA9PSAiTi1QIiwgIlAtTiIsIEFubm8pKQogIAogIHRlbXAkQW5ubzIgPSBmYWN0b3IodGVtcCRBbm5vMiwgbGV2ZWwgPSBjKCJOLU4iLCAiUC1OIiwgIlAtUCIpKQogIAogIHJldHVybih0ZW1wKQp9Cgphbm5vdGF0ZUxvb3BFbmhhbmNlciA8LSBmdW5jdGlvbihiZWRwZS5hbm5vKXsKICB0ZW1wID0gYmVkcGUuYW5ubyAlPiUgZHBseXI6OnJvd3dpc2UoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIEExID0gaWZfZWxzZSgoQTFfSDNLMjdhYyksICJFIiwgIk4iKSwKICAgICAgQTIgPSBpZl9lbHNlKChBMl9IM0syN2FjKSwgIkUiLCAiTiIpCiAgICApCiAgdGVtcCA9IHRlbXAgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEFubm8gPSBwYXN0ZTAoQTEsICItIiwgQTIpLAogICAgICAgICAgICAgICAgICBBbm5vMiA9IGlmX2Vsc2UoQW5ubyA9PSAiTi1FIiwgIkUtTiIsIEFubm8pKQogIHRlbXAkQW5ubzIgPSBmYWN0b3IodGVtcCRBbm5vMiwgbGV2ZWwgPSBjKCJOLU4iLCAiRS1OIiwgIkUtRSIpKQogIAogIHJldHVybih0ZW1wKQp9Cgphbm5vdGF0ZUxvb3BTdHJ1Y3R1cmUgPC0gZnVuY3Rpb24oYmVkcGUuYW5ubyl7CiAgdGVtcCA9IGJlZHBlLmFubm8gJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBBMSA9IGlmX2Vsc2UoKEExX0NUQ0Z8QTFfUkFEMjEpLCAiUyIsICJOIiksCiAgICAgIEEyID0gaWZfZWxzZSgoQTJfQ1RDRnxBMl9SQUQyMSksICJTIiwgIk4iKQogICAgKQogIHRlbXAgPSB0ZW1wICU+JSBkcGx5cjo6cm93d2lzZSgpICU+JQogICAgZHBseXI6Om11dGF0ZShBbm5vID0gcGFzdGUwKEExLCAiLSIsIEEyKSwKICAgICAgICAgICAgICAgICAgQW5ubzIgPSBpZl9lbHNlKEFubm8gPT0gIk4tUyIsICJTLU4iLCBBbm5vKSkKICB0ZW1wJEFubm8yID0gZmFjdG9yKHRlbXAkQW5ubzIsIGxldmVsID0gYygiTi1OIiwgIlMtTiIsICJTLVMiKSkKICByZXR1cm4odGVtcCkKfQoKCmFubm90YXRlQW5jaG9yVFNTIDwtIGZ1bmN0aW9uKGJlZHBlKXsKICB0Yi5sb29wID0gCiAgICBzZXRPdmVybGFwQ29sdW1uKCJXaHl0ZS5TRSIsCiAgICAgICAgICAgICAgICAgICAgIHNldE92ZXJsYXBDb2x1bW4oIkNUQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldE92ZXJsYXBDb2x1bW4oIlJBRDIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldE92ZXJsYXBDb2x1bW4oIkgzSzI3YWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXRPdmVybGFwQ29sdW1uKCJIM0s0bWUzVFNTIiwgYmVkcGUpKSkpKQogIHJldHVybih0Yi5sb29wKQp9CgpzZXRPdmVybGFwQ29sdW1uIDwtIGZ1bmN0aW9uKHBlYWtOYW1lLCBsb29wKXsKICB0Yi5sb29wID0gYXNfdGliYmxlKGxvb3ApCiAgb3ZlcmxhcCA9IHJldHVybk92ZXJsYXBJbmRleExpeHQoZ2V0KHBhc3RlMCgicGVhay4iLCBwZWFrTmFtZSkpLCB0Yi5sb29wKQogIHRiLmxvb3BbW3Bhc3RlMCgiQTFfIiwgcGVha05hbWUpXV0gPSBGQUxTRQogIHRiLmxvb3BbW3Bhc3RlMCgiQTFfIiwgcGVha05hbWUpXV1bb3ZlcmxhcFtbMV1dXSA9IFRSVUUKICB0Yi5sb29wW1twYXN0ZTAoIkEyXyIsIHBlYWtOYW1lKV1dID0gRkFMU0UKICB0Yi5sb29wW1twYXN0ZTAoIkEyXyIsIHBlYWtOYW1lKV1dW292ZXJsYXBbWzJdXV0gPSBUUlVFCiAgcmV0dXJuKHRiLmxvb3ApCn0KCnJldHVybk92ZXJsYXBJbmRleExpeHQgPC0gZnVuY3Rpb24ocGVhaywgbG9vcCl7CiAgYW5jaG9yMS50YiA9IGFzX3RpYmJsZShsb29wKSAlPiUgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSkKICBhbmNob3IxID0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGRhdGEuZnJhbWUoCiAgICBjaHIgPSBhbmNob3IxLnRiJGNocm9tMSwKICAgIHN0YXJ0ID0gYW5jaG9yMS50YiRzdGFydDEsCiAgICBlbmQgPSBhbmNob3IxLnRiJGVuZDEKICApKQogIAogIGFuY2hvcjIudGIgPSBhc190aWJibGUobG9vcCkgJT4lIGRwbHlyOjpzZWxlY3QoY2hyb20yLCBzdGFydDIsIGVuZDIpCiAgYW5jaG9yMiA9IG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShkYXRhLmZyYW1lKAogICAgY2hyID0gYW5jaG9yMi50YiRjaHJvbTIsCiAgICBzdGFydCA9IGFuY2hvcjIudGIkc3RhcnQyLAogICAgZW5kID0gYW5jaG9yMi50YiRlbmQyCiAgKSkKICAKICBvdmVybGFwID0gbGlzdChvdmVybGFwMSA9IHVuaXF1ZShxdWVyeUhpdHMoZmluZE92ZXJsYXBzKGFuY2hvcjEsIHBlYWspKSksCiAgICAgICAgICAgICAgICAgb3ZlcmxhcDIgPSB1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhhbmNob3IyLCBwZWFrKSkpKQogIHJldHVybihvdmVybGFwKQp9CgpzYXZlQW5ub0dyb3VwQmVkcGUgPC0gZnVuY3Rpb24odGVtcCwgYW5uby5saXN0LCBuYW1lLCBhbm5vTmFtZSwgb3VEaXIpewogIGxvb3AgPSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYW5uby5saXN0KSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoYygiY2hyb20xIiwgInN0YXJ0MSIsICJlbmQxIiwgImNocm9tMiIsICJzdGFydDIiLCAiZW5kMiIpKQogIGZ3cml0ZShsb29wLCBoZXJlKG91dERpciwgcGFzdGUwKG5hbWUsICJfIiwgYW5ub05hbWUsICIuYmVkcGUiKSksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQp9CmBgYAojIyMjIEFubm90YXRpb24KYGBge3J9CmNvbnNlbnN1cy5sb29wLnRiIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfc2NvcmUudHN2IikpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEZpbHRlcmluZyBIM0s0bWUzIHBlYWtzIHRoYXQgaGFzIFRTUyBuZWFyYnkKIyBTaW5jZSB0aGUgZmluZXN0IHJlc29sdXRpb24gaXMgNWtiLCArLTIuNWtiIHdpbGwgYmUgdXNlZCBhcyBhIGN1dG9mZiBmb3IgY2hlY2tpbmcgVFNTIHByZXNlbmNlCmZsYW5rU2l6ZSA8LSAyNTAwCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLAogICAgICAgICAgICAgICAgVFNTc3RhcnQgPSBUU1MgLSBmbGFua1NpemUsCiAgICAgICAgICAgICAgICBUU1NlbmQgPSBUU1MgKyBmbGFua1NpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIFRTU3N0YXJ0LCBUU1NlbmQpCmNvbG5hbWVzKGdlbmUudGIpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQpUU1Mxa2IuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGdlbmUudGIpCnRlbXAgPC0gcGVhay5IM0s0bWUzW3VuaXF1ZShxdWVyeUhpdHMoZmluZE92ZXJsYXBzKHBlYWsuSDNLNG1lMywgVFNTMWtiLmdyKSkpXQpmd3JpdGUoYXNfdGliYmxlKHRlbXApLCBoZXJlKHJlZkRpciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxhbmtTaXplLzEwMDAsICJrYlRTUy5iZWQiKSksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQpwZWFrLkgzSzRtZTNUU1MgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgcGFzdGUwKCIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxhbmtTaXplLzEwMDAsICJrYlRTUy5iZWQiKSkpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQW5ub3RhdGluZyB3aXRoIHN0cmljdCBwcmlvcml0eSAoUC1UU1MgPiBFID4gUykKdGVtcC5hbm5vLlRTUyA8LSBhbm5vdGF0ZUFuY2hvclRTUyhjb25zZW5zdXMubG9vcC50YikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGRpZmZfZFRBR19ETVNPID0gKGRUQUctRE1TTyksCiAgICBkaWZmX0E0ODVfRE1TTyA9IChBNDg1LURNU08pKQoKbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKY29uc2Vuc3VzLmxvb3AuYW5uby50YiA8LSBhbm5vdGF0ZUxvb3BSZWxheGVkVFNTKHRlbXAuYW5uby5UU1MpCmZ3cml0ZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpLCAKICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IFRSVUUpCmNyZWF0ZUxvb3BBbm5vdGF0aW9uKGNvbnNlbnN1cy5sb29wLmFubm8udGIsIG5hbWUsIGZpZ0Rpciwgb3V0RGlyLCAgY29sb3JMaXN0TG9vcCkKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8udGIsIHVuaXF1ZShjb25zZW5zdXMubG9vcC5hbm5vLnRiJEFubm8yKSAsIG5hbWUsICJhbGwiLCBvdXREaXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiLCAiRS1FIiwgIkUtUyIsICJFLVgiKSwgbmFtZSwgInJlZ3VsYXRvcnkiLCBvdXREaXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBjKCJTLVMiLCAiUy1YIiksIG5hbWUsICJzdHJ1Y3R1cmUiLCBvdXREaXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBjKCJYLVgiKSwgbmFtZSwgIngteCIsIG91dERpcikKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8udGIsIGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpLCBuYW1lLCAicC1uIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby50YiwgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgbmFtZSwgInBlLXBlIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby50YiwgYygiUC1QIiwgIlAtRSIpLCBuYW1lLCAicC1wZSIsIG91dERpcikKCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBjKCJQLVAiKSwgbmFtZSwgInAtcCIsIG91dERpcikKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8udGIsIGMoIlAtRSIpLCBuYW1lLCAicC1lIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby50YiwgYygiUC1TIiksIG5hbWUsICJwLXMiLCBvdXREaXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnRiLCBjKCJQLVgiKSwgbmFtZSwgInAteCIsIG91dERpcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQW5ub3RhdGluZyB3aXRoIG9uZSBtYXJrZXIgKFByb21vdGVyKQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vUHJvbW90ZXIiCmNvbnNlbnN1cy5sb29wLmFubm8ucHJvbW90ZXIudGIgPC0gYW5ub3RhdGVMb29wUHJvbW90ZXJUU1ModGVtcC5hbm5vLlRTUykKZndyaXRlKGNvbnNlbnN1cy5sb29wLmFubm8ucHJvbW90ZXIudGIsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSksIAogICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gVFJVRSkKY3JlYXRlTG9vcEFubm90YXRpb24oY29uc2Vuc3VzLmxvb3AuYW5uby5wcm9tb3Rlci50YiwgbmFtZSwgCiAgICAgICAgICAgICAgICAgICAgIGZpZ0Rpciwgb3V0RGlyLCAgY29sb3JMaXN0UHJvbW90ZXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnByb21vdGVyLnRiLCB1bmlxdWUoY29uc2Vuc3VzLmxvb3AuYW5uby5wcm9tb3Rlci50YiRBbm5vMikgLCBuYW1lLCAiYWxsIiwgb3V0RGlyKSAgCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLnByb21vdGVyLnRiLCBjKCJQLVAiKSwgbmFtZSwgInAtcCIsIG91dERpcikKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8ucHJvbW90ZXIudGIsIGMoIlAtTiIpLCBuYW1lLCAicC1uIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5wcm9tb3Rlci50YiwgYygiTi1OIiksIG5hbWUsICJuLW4iLCBvdXREaXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEFubm90YXRpbmcgd2l0aCBvbmUgbWFya2VyIChFbmhhbmNlcikKbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0VuaGFuY2VyIgpjb25zZW5zdXMubG9vcC5hbm5vLmVuaGFuY2VyLnRiIDwtIGFubm90YXRlTG9vcEVuaGFuY2VyKHRlbXAuYW5uby5UU1MpCmZ3cml0ZShjb25zZW5zdXMubG9vcC5hbm5vLmVuaGFuY2VyLnRiLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpLCAKICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IFRSVUUpCmNyZWF0ZUxvb3BBbm5vdGF0aW9uKGNvbnNlbnN1cy5sb29wLmFubm8uZW5oYW5jZXIudGIsIG5hbWUsIAogICAgICAgICAgICAgICAgICAgICBmaWdEaXIsIG91dERpciwgIGNvbG9yTGlzdEVuaGFuY2VyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5lbmhhbmNlci50YiwgdW5pcXVlKGNvbnNlbnN1cy5sb29wLmFubm8uZW5oYW5jZXIudGIkQW5ubzIpICwgbmFtZSwgImFsbCIsIG91dERpcikgIApzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5lbmhhbmNlci50YiwgYygiRS1FIiksIG5hbWUsICJlLWUiLCBvdXREaXIpCnNhdmVBbm5vR3JvdXBCZWRwZShjb25zZW5zdXMubG9vcC5hbm5vLmVuaGFuY2VyLnRiLCBjKCJFLU4iKSwgbmFtZSwgImUtbiIsIG91dERpcikKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8uZW5oYW5jZXIudGIsIGMoIk4tTiIpLCBuYW1lLCAibi1uIiwgb3V0RGlyKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEFubm90YXRpbmcgd2l0aCBvbmUgbWFya2VyIChTdHJ1Y3R1cmUpCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9TdHJ1Y3R1cmUiCmNvbnNlbnN1cy5sb29wLmFubm8uc3RydWN0dXJlLnRiIDwtIGFubm90YXRlTG9vcFN0cnVjdHVyZSh0ZW1wLmFubm8uVFNTKQpmd3JpdGUoY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSksIAogICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gVFJVRSkKY3JlYXRlTG9vcEFubm90YXRpb24oY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIsIG5hbWUsIAogICAgICAgICAgICAgICAgICAgICBmaWdEaXIsIG91dERpciwgIGNvbG9yTGlzdFN0cnVjdHVyZSkKc2F2ZUFubm9Hcm91cEJlZHBlKGNvbnNlbnN1cy5sb29wLmFubm8uc3RydWN0dXJlLnRiLCB1bmlxdWUoY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIkQW5ubzIpICwgbmFtZSwgImFsbCIsIG91dERpcikgIApzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIsIGMoIlMtUyIpLCBuYW1lLCAicy1zIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIsIGMoIlMtTiIpLCBuYW1lLCAicy1uIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUoY29uc2Vuc3VzLmxvb3AuYW5uby5zdHJ1Y3R1cmUudGIsIGMoIk4tTiIpLCBuYW1lLCAibi1uIiwgb3V0RGlyKQpgYGAKCiMjIyMjIFB1cmUtcmVnIHZzIFN0ci1yZWcKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgMjAyNC4wOS4xMCBTcGxpdHRpbmcgcmVndWxhdG9yeSBsb29wIGludG8gcHVyZSByZWd1bGF0b3J5IGFuZCBzdHJ1Y3R1cmUtcmVsYXRlZCBsb29wcwpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5Igpjb25zZW5zdXMubG9vcC5hbm5vLnRiIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCnJlZ3VsYXRvcnkubG9vcC5hbm5vLnRiIDwtIGNvbnNlbnN1cy5sb29wLmFubm8udGIgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKQoKcmVndWxhdG9yeS5sb29wLmFubm8udGIgPC0gcmVndWxhdG9yeS5sb29wLmFubm8udGIgJT4lIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgQW5ubzMgPSBpZmVsc2UoQTFfUkFEMjEgfCBBMV9DVENGIHwgQTJfUkFEMjEgfCBBMl9SQUQyMSwgcGFzdGUwKCJzdHIiKSwKICAgICAgICAgICAgICAgICAgIHBhc3RlMCgicmVnIikpCiAgKQoKCmZ3cml0ZShyZWd1bGF0b3J5Lmxvb3AuYW5uby50YiwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX0Fubm8zLnRzdiIpKSwgCiAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBUUlVFKQoKcmVndWxhdG9yeS5sb29wLmFubm8udGJfcmVnIDwtIHJlZ3VsYXRvcnkubG9vcC5hbm5vLnRiICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8zID09ICJyZWciKQpyZWd1bGF0b3J5Lmxvb3AuYW5uby50Yl9zdHIgPC0gcmVndWxhdG9yeS5sb29wLmFubm8udGIgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzMgPT0gInN0ciIpCgpzYXZlQW5ub0dyb3VwQmVkcGUocmVndWxhdG9yeS5sb29wLmFubm8udGJfcmVnLCBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBuYW1lLCAicGUtcGVfcmVnIiwgb3V0RGlyKQpzYXZlQW5ub0dyb3VwQmVkcGUocmVndWxhdG9yeS5sb29wLmFubm8udGJfc3RyLCBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBuYW1lLCAicGUtcGVfc3RyIiwgb3V0RGlyKQoKYGBgCgoKIyMjIFsyLjZdIENvbXBhcmluZyBhY3Jvc3Mgc2FtcGxlcyBmb3IgY29uZXNuc3VzIGxvb3AKIyMjIyBGdW5jdGlvbnMKYGBge3J9CmNyZWF0ZV9sb29wX2Rpc192c19zY29yZSA8LSBmdW5jdGlvbihkYXRhLCBmaWdEaXIsIG5hbWUsIEFubm8yTGlzdCl7CiAgZGF0YSA9IGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBBbm5vMkxpc3QpCiAgCiAgIyMjIGJhcnBsb3QKICB0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoaWQsIERNU08sIGRUQUcsIEE0ODUpICU+JQogICAgcGl2b3RfbG9uZ2VyKCFpZCwgbmFtZXNfdG8gPSAidHJlYXRtZW50IiwgdmFsdWVzX3RvID0gInNjb3JlIikKICB0ZW1wJHRyZWF0bWVudCA8LSBmYWN0b3IodGVtcCR0cmVhdG1lbnQsIGxldmVscyA9IGMoIkRNU08iLCAiZFRBRyIsICJBNDg1IikpCiAgCiAgcDMgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gdHJlYXRtZW50LCB5ID0gc2NvcmUpKSArCiAgICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHRyZWF0bWVudCksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkRNU08iID0gImdyZXkiLCAiZFRBRyIgPSAicGluayIsICJBNDg1IiA9ICJza3libHVlIikpICsKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICB5bGltKC0wLjUsIDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXkiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgZ2d0aXRsZShuYW1lKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA0KSkKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNjb3JlX2JhcnBsb3RfIiwgbmFtZSkKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIAogICAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAyLCBoZWlnaHQgPSA0KQogIHByaW50KHAzKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIAogICAgICAgICAgd2lkdGggPSAyLCBoZWlnaHQgPSA0KQogIHByaW50KHAzKQogIGRldi5vZmYoKQogIAogICMjIyBEaXN0YW5jZSB2cyBzY29yZQogIAogIHRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIERNU08sIGRUQUcsIEE0ODUpCgogIGF2Z19zY29yZXMgPC0gdGVtcCAlPiUKICAgIGdyb3VwX2J5KGRpc3RhbmNlKSAlPiUKICAgIHN1bW1hcmlzZShhY3Jvc3Moc3RhcnRzX3dpdGgoIkRNU08iKTpzdGFydHNfd2l0aCgiQTQ4NSIpLCBtZWFuLCBuYS5ybSA9IFRSVUUpKQoKICBhdmdfc2NvcmVzX2xvbmcgPC0gYXZnX3Njb3JlcyAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gRE1TTzpBNDg1LCBuYW1lc190byA9ICJjb25kaXRpb24iLCB2YWx1ZXNfdG8gPSAiYXZnX3Njb3JlIikKICBhdmdfc2NvcmVzX2xvbmckY29uZGl0aW9uIDwtIGZhY3Rvcihhdmdfc2NvcmVzX2xvbmckY29uZGl0aW9uLCBsZXZlbHMgPSBjKCJETVNPIiwgImRUQUciLCAiQTQ4NSIpKQogICMgQ3JlYXRlIHRoZSBwbG90CiAgcDQgPC0gZ2dwbG90KGF2Z19zY29yZXNfbG9uZywgYWVzKHggPSBkaXN0YW5jZSwgeSA9IGF2Z19zY29yZSwgY29sb3IgPSBjb25kaXRpb24sIGZpbGwgPSBjb25kaXRpb24pKSArCiAgICBnZW9tX3Ntb290aChzaG93LmxlZ2VuZCA9IFRSVUUpICsgeWxpbSgwLCAwLjUpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJETVNPIiA9ICJncmV5IiwgImRUQUciID0gInBpbmsiLCAiQTQ4NSIgPSAic2t5Ymx1ZSIpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJETVNPIiA9ICJncmV5ODAiLCAiZFRBRyIgPSAicGluayIsICJBNDg1IiA9ICJza3libHVlIikpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobmFtZSksCiAgICAgICAgIHggPSAiRGlzdGFuY2UiLAogICAgICAgICB5ID0gIkF2ZXJhZ2UgU2NvcmUiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA1KSkKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImRpc3RfdnNfc2NvcmVfbGluZVBsb3RfIiwgbmFtZSkKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksCiAgICAgIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMpCiAgcHJpbnQocDQpCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwKICAgICAgd2lkdGggPSA0LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQp9CgpjcmVhdGVfbG9vcF9kaXNfdnNfZGlmZnNjb3JlIDwtIGZ1bmN0aW9uKGRhdGEsIGZpZ0RpciwgbmFtZSwgQW5ubzJMaXN0KXsKICBkYXRhID0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIEFubm8yTGlzdCkKICAKICAKICB0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkaWZmX2RUQUdfRE1TTywgZGlmZl9BNDg1X0RNU08pCiAgCiAgYXZnX3Njb3JlcyA8LSB0ZW1wICU+JQogICAgZ3JvdXBfYnkoZGlzdGFuY2UpICU+JQogICAgc3VtbWFyaXNlKGFjcm9zcygxOjIsIG1lYW4sIG5hLnJtID0gVFJVRSkpCiAgCiAgYXZnX3Njb3Jlc19sb25nIDwtIGF2Z19zY29yZXMgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IDI6MywgbmFtZXNfdG8gPSAiY29uZGl0aW9uIiwgdmFsdWVzX3RvID0gImF2Z19zY29yZSIpCiAgYXZnX3Njb3Jlc19sb25nJGNvbmRpdGlvbiA8LSBmYWN0b3IoYXZnX3Njb3Jlc19sb25nJGNvbmRpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiZGlmZl9kVEFHX0RNU08iLCAiZGlmZl9BNDg1X0RNU08iKSkKICAjIENyZWF0ZSB0aGUgcGxvdAogIHA0IDwtIGdncGxvdChhdmdfc2NvcmVzX2xvbmcsIGFlcyh4ID0gZGlzdGFuY2UsIHkgPSBhdmdfc2NvcmUsIGNvbG9yID0gY29uZGl0aW9uLCBmaWxsID0gY29uZGl0aW9uKSkgKwogICAgZ2VvbV9zbW9vdGgoc2hvdy5sZWdlbmQgPSBUUlVFKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsgeWxpbSgtMC41LCAwLjEpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJkaWZmX2RUQUdfRE1TTyIgPSAicGluayIsICJkaWZmX0E0ODVfRE1TTyIgPSAic2t5Ymx1ZSIpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkaWZmX2RUQUdfRE1TTyIgPSAicGluayIsICJkaWZmX0E0ODVfRE1TTyIgPSAic2t5Ymx1ZSIpKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG5hbWUpLAogICAgICAgICB4ID0gIkRpc3RhbmNlIiwKICAgICAgICAgeSA9ICJBdmVyYWdlIERpZmYgU2NvcmUiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA1KSkKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImRpc3RfdnNfc2NvcmVfZGlmZmxpbmVQbG90XyIsIG5hbWUpCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLAogICAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMpCiAgcHJpbnQocDQpCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwKICAgICAgICAgIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQp9CgpjcmVhdGVfbG9vcF9zY2F0dGVycGxvdCA8LSBmdW5jdGlvbihkYXRhLCBmaWdEaXIsIG5hbWUsIEFubm8yTGlzdCwgZGlmZkN1dG9mZil7CiAgZGF0YSA8LSBkYXRhICU+JQogICAgZHBseXI6Om11dGF0ZSh1cGRvd25fZFRBR19ETVNPID0gaWZlbHNlKGRpZmZfZFRBR19ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZfZFRBR19ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpLAogICAgICAgICAgICAgICAgICB1cGRvd25fQTQ4NV9ETVNPID0gaWZlbHNlKGRpZmZfQTQ4NV9ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZfQTQ4NV9ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBBbm5vMkxpc3QpCiAgZGF0YSR1cGRvd25fZFRBR19ETVNPIDwtIGZhY3RvcihkYXRhJHVwZG93bl9kVEFHX0RNU08sIGxldmVscyA9IGMoIlVQIiwgIk5PIiwgIkRPV04iKSkKICBkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIAogIG51bS51cCA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9kVEFHX0RNU08pKVsiVVAiXQogIG51bS5ubyA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9kVEFHX0RNU08pKVsiTk8iXQogIG51bS5kb3duIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJET1dOIl0KICBudW0uYWxsIDwtIG51bS51cCArIG51bS5ubyArIG51bS5kb3duCiAgcGVyYy51cCA8LSByb3VuZChudW0udXAgLyBudW0uYWxsICogMTAwLCAyKQogIHBlcmMubm8gPC0gcm91bmQobnVtLm5vIC8gbnVtLmFsbCAqIDEwMCwgMikKICBwZXJjLmRvd24gPC0gcm91bmQobnVtLmRvd24gLyBudW0uYWxsICogMTAwLCAyKQogIAogICMjIyBTY2F0dGVycGxvdAogIGRhdGEkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShkYXRhJERNU08sIGRhdGEkZFRBRywgbiA9IDEwMCkKICBkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgY29ycmVsYXRpb24gPC0gY29yKGRhdGEkRE1TTywgZGF0YSRkVEFHKQogIHAxIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IERNU08sIHkgPSBkVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAxLAogICAgICBhbHBoYSA9IDEsCiAgICAgIHN0cm9rZSA9IDApICsgCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJEIiwgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IDEuNS81LjA4LCAgIyBBZGp1c3Qgd2lkdGggb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IDE1LzUuMDggICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArIGNvb3JkX2ZpeGVkKCkgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiLAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IiwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZTAoIlVQOiAiLCBudW0udXAsICIgKCIsIHBlcmMudXAsICIlKSIpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCAsIHNpemUgPSAxLAogICAgICAgIGZhbWlseSA9IGZvbnRUeXBlKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMS0wLjEsIGxhYmVsID0gcGFzdGUwKCJOTzogIiwgbnVtLm5vLCAiICgiLCBwZXJjLm5vLCAiJSkiKSwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgLCBzaXplID0gMSwKICAgICAgICBmYW1pbHkgPSBmb250VHlwZSkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEtMC4yLCBsYWJlbCA9IHBhc3RlMCgiRE9XTjogIiwgbnVtLmRvd24sICIgKCIsIHBlcmMuZG93biwgIiUpIiksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsICwgc2l6ZSA9IDEsCiAgICAgICAgZmFtaWx5ID0gZm9udFR5cGUpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAjYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUoInIgPSIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSksIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lKAogICAgICAjIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBoanVzdCA9IDAuNSwKICAgICAgICBzaXplID0gZm9udFNpemVTLAogICAgICAgIGZhbWlseSA9IGZvbnRUeXBlCiAgICAgICksCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgICApLAogICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgICApLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICAgICksCiAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICAgICksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgKSArCiAgeGxhYigiTG9vcCBzY29yZVxuRzEuRE1TTyIpICsKICAgIHlsYWIoIkxvb3Agc2NvcmVcbkcxLmRUQUciKQogIAogIAogIAogIG51bS51cCA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9BNDg1X0RNU08pKVsiVVAiXQogIG51bS5ubyA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9BNDg1X0RNU08pKVsiTk8iXQogIG51bS5kb3duIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX0E0ODVfRE1TTykpWyJET1dOIl0KICBudW0uYWxsIDwtIG51bS51cCArIG51bS5ubyArIG51bS5kb3duCiAgcGVyYy51cCA8LSByb3VuZChudW0udXAgLyBudW0uYWxsICogMTAwLCAyKQogIHBlcmMubm8gPC0gcm91bmQobnVtLm5vIC8gbnVtLmFsbCAqIDEwMCwgMikKICBwZXJjLmRvd24gPC0gcm91bmQobnVtLmRvd24gLyBudW0uYWxsICogMTAwLCAyKQogIAogIGRhdGEkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShkYXRhJERNU08sIGRhdGEkQTQ4NSwgbiA9IDEwMCkKICBkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgY29ycmVsYXRpb24gPC0gY29yKGRhdGEkRE1TTywgZGF0YSRBNDg1KQogIHAyIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IERNU08sIHkgPSBBNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAxLAogICAgICBhbHBoYSA9IDEsCiAgICAgIHN0cm9rZSA9IDApICsgCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJEIiwgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IDEuNS81LjA4LCAgIyBBZGp1c3Qgd2lkdGggb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IDE1LzUuMDggICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArIGNvb3JkX2ZpeGVkKCkgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiLAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IiwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZTAoIlVQOiAiLCBudW0udXAsICIgKCIsIHBlcmMudXAsICIlKSIpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSwKICAgICAgICBmYW1pbHkgPSBmb250VHlwZSkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEtMC4xLCBsYWJlbCA9IHBhc3RlMCgiTk86ICIsIG51bS5ubywgIiAoIiwgcGVyYy5ubywgIiUpIiksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxLAogICAgICAgIGZhbWlseSA9IGZvbnRUeXBlKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMS0wLjIsIGxhYmVsID0gcGFzdGUwKCJET1dOOiAiLCBudW0uZG93biwgIiAoIiwgcGVyYy5kb3duLCAiJSkiKSwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEsCiAgICAgICAgZmFtaWx5ID0gZm9udFR5cGUpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIAogICAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMSwgbGFiZWwgPSBwYXN0ZSgiciA9Iiwgcm91bmQoY29ycmVsYXRpb24sIDIpKSwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWUoCiAgICAgICMgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGhqdXN0ID0gMC41LAogICAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgICAgZmFtaWx5ID0gZm9udFR5cGUKICAgICAgKSwKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVTLAogICAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICAgICksCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVTLAogICAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICAgICksCiAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICApICsKICAgIHhsYWIoIkxvb3Agc2NvcmVcbkcxLkRNU08iKSArCiAgICB5bGFiKCJMb29wIHNjb3JlXG5HMS5BNDg1IikKCiAgICB3aWR0aCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaAogIGhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaCAgCiAgCiAgZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIscGFzdGUwKCJzY2F0dGVycGxvdF8iLCBuYW1lLCAiX2RUQUdfdnNfRE1TT18iLCBkaWZmQ3V0b2ZmKSkKCiAgc3ZnbGl0ZShwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIiksIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9aGVpZ2h0KQogIHByaW50KHAxKQogIGRldi5vZmYoKQogIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9aGVpZ2h0LCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iKQogIHByaW50KHAxKQogIGRldi5vZmYoKQogIAogICAgZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgic2NhdHRlcnBsb3RfIiwgbmFtZSwgIl9BNDg1X3ZzX0RNU09fIiwgZGlmZkN1dG9mZikpCgogIHN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPWhlaWdodCkKICBwcmludChwMikKICBkZXYub2ZmKCkKICBwbmcocGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPWhlaWdodCwgcmVzID0gNjAwLCB1bml0ID0gImluIikKICBwcmludChwMikKICBkZXYub2ZmKCkKICAKICAjIAogICMgCiAgIyAKICAjIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNSoxLjUsIGhlaWdodCA9IDIuNSoxLjUpCiAgIyBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCiAgIyBkZXYub2ZmKCkKICAjIAogICMgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgCiAgIyAgICAgICAgIHdpZHRoID0gNSoxLjUsIGhlaWdodCA9IDIuNSoxLjUpCiAgIyBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCiAgIyBkZXYub2ZmKCkKfQoKbWFrZV9kaWZmX2JlZHBlIDwtIGZ1bmN0aW9uKGRhdGEsIG5hbWUsIEFubm8yTGlzdCwgb3V0RGlyLCBkaWZmQ3V0b2ZmKXsKICBkYXRhIDwtIGRhdGEgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSkpICU+JQogICAgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIEFubm8yTGlzdCkKICBkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIGRhdGEkdXBkb3duX0E0ODVfRE1TTyA8LSBmYWN0b3IoZGF0YSR1cGRvd25fQTQ4NV9ETVNPLCBsZXZlbHMgPSBjKCJVUCIsICJOTyIsICJET1dOIikpCiAgCiAgb3V0LnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fZFRBR19ETVNPID09ICJVUCIpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNikpCiAgZndyaXRlKG91dC50ZW1wLCBoZXJlKG91dERpciwgcGFzdGUwKG5hbWUsICJfZFRBR3ZzRE1TT19VUF9kaWZmIiwgZGlmZkN1dG9mZiwgIi5iZWRwZSIpKSwgCiAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQogIG91dC50ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX2RUQUdfRE1TTyA9PSAiTk8iKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDQsIDUsIDYpKQogIGZ3cml0ZShvdXQudGVtcCwgaGVyZShvdXREaXIsIHBhc3RlMChuYW1lLCAiX2RUQUd2c0RNU09fTk9fZGlmZiIsIGRpZmZDdXRvZmYsICIuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKICBvdXQudGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9kVEFHX0RNU08gPT0gIkRPV04iKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDQsIDUsIDYpKQogIGZ3cml0ZShvdXQudGVtcCwgaGVyZShvdXREaXIsIHBhc3RlMChuYW1lLCAiX2RUQUd2c0RNU09fRE9XTl9kaWZmIiwgZGlmZkN1dG9mZiwgIi5iZWRwZSIpKSwgCiAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQogIAogIG91dC50ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX0E0ODVfRE1TTyA9PSAiVVAiKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDQsIDUsIDYpKQogIGZ3cml0ZShvdXQudGVtcCwgaGVyZShvdXREaXIsIHBhc3RlMChuYW1lLCAiX0E0ODV2c0RNU09fVVBfZGlmZiIsIGRpZmZDdXRvZmYsICIuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKICBvdXQudGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9BNDg1X0RNU08gPT0gIk5PIikgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2KSkKICBmd3JpdGUob3V0LnRlbXAsIGhlcmUob3V0RGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1dnNETVNPX05PX2RpZmYiLCBkaWZmQ3V0b2ZmLCAiLmJlZHBlIikpLCAKICAgICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCiAgb3V0LnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fQTQ4NV9ETVNPID09ICJET1dOIikgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2KSkKICBmd3JpdGUob3V0LnRlbXAsIGhlcmUob3V0RGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1dnNETVNPX0RPV05fZGlmZiIsIGRpZmZDdXRvZmYsICIuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKfQoKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50IDwtIGZ1bmN0aW9uKGRhdGEsIGZpZ0RpciwgbmFtZSwgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBGQUxTRSl7CiAgYXZnX3Njb3Jlc19sb25nIDwtIGRhdGEgJT4lCiAgICBncm91cF9ieShkaXN0YW5jZSwgQW5ubzIpICU+JQogICAgc3VtbWFyaXNlKGF2Z19zY29yZSA9IG1lYW4oc2NvcmUsIG5hLnJtID0gVFJVRSkpICU+JQogICAgdW5ncm91cCgpIAogIGF2Z19zY29yZXNfbG9uZyRBbm5vMiA8LSBmYWN0b3IoYXZnX3Njb3Jlc19sb25nJEFubm8yLCBsZXZlbCA9IGxvb3BMaXN0KQogIHA0IDwtIGdncGxvdChhdmdfc2NvcmVzX2xvbmcsIGFlcyh4ID0gZGlzdGFuY2UsIHkgPSBhdmdfc2NvcmUsIGNvbG9yID0gQW5ubzIsIGZpbGwgPSBBbm5vMikpICsgCiAgICBnZW9tX3Ntb290aChzaG93LmxlZ2VuZCA9IFRSVUUsIHNlID0gc2UpICArCiAgICB5bGltKDAsIDAuNSkgKwogICAgdGhlbWVfY2xhc3NpYygpICsgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JMaXN0KSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG5hbWUpLAogICAgICAgICB4ID0gIkRpc3RhbmNlIiwKICAgICAgICAgeSA9ICJBdmVyYWdlIFNjb3JlIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJkaXN0X3ZzX3Njb3JlX2xpbmVQbG90XyIsIG5hbWUpCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCAKICAgICAgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMykKICBwcmludChwNCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICAgIHdpZHRoID0gNCwgaGVpZ2h0ID0gMykKICBwcmludChwNCkKICBkZXYub2ZmKCkKfSAKCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnQgPC0gZnVuY3Rpb24oZGF0YSwgZmlnRGlyLCBuYW1lLCBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IEZBTFNFKXsKICBhdmdfc2NvcmVzX2xvbmcgPC0gZGF0YSAlPiUKICAgIGdyb3VwX2J5KGRpc3RhbmNlLCBBbm5vMikgJT4lCiAgICBzdW1tYXJpc2UoYXZnX3Njb3JlID0gbWVhbihzY29yZSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICB1bmdyb3VwKCkgCiAgYXZnX3Njb3Jlc19sb25nJEFubm8yIDwtIGZhY3Rvcihhdmdfc2NvcmVzX2xvbmckQW5ubzIsIGxldmVsID0gbG9vcExpc3QpCiAgcDQgPC0gZ2dwbG90KGF2Z19zY29yZXNfbG9uZywgYWVzKHggPSBkaXN0YW5jZSwgeSA9IGF2Z19zY29yZSwgY29sb3IgPSBBbm5vMiwgZmlsbCA9IEFubm8yKSkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgIGdlb21fc21vb3RoKHNob3cubGVnZW5kID0gVFJVRSwgc2UgPSBzZSkgICsKICAgIHRoZW1lX2NsYXNzaWMoKSArICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvckxpc3QpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlMChuYW1lKSwKICAgICAgICAgeCA9ICJEaXN0YW5jZSIsCiAgICAgICAgIHkgPSAiQXZlcmFnZSBEaWZmIFNjb3JlIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZGlzdF92c19zY29yZV9kaWZmbGluZVBsb3RfIiwgbmFtZSkKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIAogICAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIAogICAgICAgICAgd2lkdGggPSA0LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQp9IAoKY3JlYXRlX3Njb3JlX2JhcnBsb3RfcGVyVHJlYXRtZW50IDwtIGZ1bmN0aW9uKGRhdGEsIGZpZ0RpciwgbmFtZSwgbG9vcExpc3QsIGNvbG9yTGlzdCl7CiAgZGF0YSRBbm5vMiA8LSBmYWN0b3IoZGF0YSRBbm5vMiwgbGV2ZWxzID0gbG9vcExpc3QpCiAgCiAgcDMgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gQW5ubzIsIHkgPSBzY29yZSkpICsKICAgIGdlb21fdmlvbGluKGFlcyhmaWxsID0gQW5ubzIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvckxpc3QpICsKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICB5bGltKC0wLjUsIDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXkiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgZ2d0aXRsZShuYW1lKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA0KSkKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNjb3JlX2JhclBsb3RfIiwgbmFtZSkKICAKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIAogICAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAyLCBoZWlnaHQgPSA0KQogIHByaW50KHAzKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIAogICAgICAgICAgd2lkdGggPSAyLCBoZWlnaHQgPSA0KQogIHByaW50KHAzKQp9CgoKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyA8LSBmdW5jdGlvbihkYXRhLCBmaWdEaXIsIGdyb3VwTmFtZSwgYW5ub0xpc3QpewogICMgY3JlYXRlX2xvb3BfZGlzX3ZzX3Njb3JlKGRhdGEsIGZpZ0RpciwgZ3JvdXBOYW1lLCBhbm5vTGlzdCkKICAjIGNyZWF0ZV9sb29wX2Rpc192c19kaWZmc2NvcmUoZGF0YSwgZmlnRGlyLCBncm91cE5hbWUsIGFubm9MaXN0KQoKICBjcmVhdGVfbG9vcF9zY2F0dGVycGxvdChkYXRhLCBmaWdEaXIsIGdyb3VwTmFtZSwgYW5ub0xpc3QsIDAuMikKICAjIGNyZWF0ZV9sb29wX3NjYXR0ZXJwbG90KGRhdGEsIGZpZ0RpciwgZ3JvdXBOYW1lLCBhbm5vTGlzdCwgMC4xKQogICMgbWFrZV9kaWZmX2JlZHBlKGRhdGEsIGdyb3VwTmFtZSwgYW5ub0xpc3QsIGNvbnNlbnN1c0RpciwgMC4yKQogICMgbWFrZV9kaWZmX2JlZHBlKGRhdGEsIGdyb3VwTmFtZSwgYW5ub0xpc3QsIGNvbnNlbnN1c0RpciwgMC4xKQp9CmBgYAoKIyMjIyBSZWxheGVkIGFubm90YXRpb24KYGBge3J9CgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCgppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgImNsX2FsbCIpLCB1bmlxdWUoZGF0YSRBbm5vMikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAiY2xfc3RydWN0dXJlIiksIAogICAgICAgICAgICAgICAgICAgICAgIGMoIlMtUyIsICJTLVgiKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJzLXMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYygiUy1TIikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAiY2xfcmVndWxhdG9yeSIpLCAKICAgICAgICAgICAgICAgICAgICAgICBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiLCAiRS1FIiwgIkUtUyIsICJFLVgiKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJjbF9wZS1wZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgInAtcGUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYygiUC1QIiwgIlAtRSIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgInAtcCIpLCAKICAgICAgICAgICAgICAgICAgICAgICBjKCJQLVAiKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJwLWUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYygiUC1FIikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAiZS1lIiksIAogICAgICAgICAgICAgICAgICAgICAgIGMoIkUtRSIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgIngteCIpLCAKICAgICAgICAgICAgICAgICAgICAgICBjKCJYLVgiKSkKIyMjIyMjIyMjIyMKIyBDcmVhdGluZyBkaWZmZXJlbnRpYWwgc2NhdHRlcnBsb3QKVmlldyhkYXRhKQoKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENyZWF0aW5nIGZpZ3VyZXMgcGVyIGVhY2ggY29uZGl0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfRE1TTyIpLCBjKCJYLVgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTLVgiLCAiUy1TIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRS1YIiwiRS1TIiwiRS1FIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUC1FIiwiUC1YIiwgIlAtUyIsICJQLVAiKSwgY29sb3JMaXN0TG9vcCkKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgZFRBRywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfZFRBRyIpLCBjKCJYLVgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTLVgiLCAiUy1TIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRS1YIiwiRS1TIiwiRS1FIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUC1FIiwiUC1YIiwgIlAtUyIsICJQLVAiKSwgY29sb3JMaXN0TG9vcCkKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIEE0ODUsIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z1Njb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODUiKSwgYygiWC1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUy1YIiwgIlMtUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkUtWCIsIkUtUyIsIkUtRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlAtRSIsIlAtWCIsICJQLVMiLCAiUC1QIiksIGNvbG9yTGlzdExvb3ApCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENyZWF0aW5nIGZpZ3VyZXMgcGVyIGVhY2ggY29uZGl0aW9uLCBkaWZmZXJlbnRpYWwKbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkaWZmX2RUQUdfRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnRGlmZlNjb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2RUQUciKSwgYygiWC1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUy1YIiwgIlMtUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkUtWCIsIkUtUyIsIkUtRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlAtRSIsIlAtWCIsICJQLVMiLCAiUC1QIiksIGNvbG9yTGlzdExvb3ApCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHX1NFIiksIGMoIlgtWCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlMtWCIsICJTLVMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFLVgiLCJFLVMiLCJFLUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQLUUiLCJQLVgiLCAiUC1TIiwgIlAtUCIpLCBjb2xvckxpc3RMb29wLCBzZSA9IFRSVUUpCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgZGlmZl9BNDg1X0RNU08sIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1IiksIGMoIlgtWCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlMtWCIsICJTLVMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFLVgiLCJFLVMiLCJFLUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQLUUiLCJQLVgiLCAiUC1TIiwgIlAtUCIpLCBjb2xvckxpc3RMb29wKQoKY3JlYXRlX2Rpc3RfdnNfYXZnRGlmZlNjb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODVfU0UiKSwgYygiWC1YIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUy1YIiwgIlMtUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkUtWCIsIkUtUyIsIkUtRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlAtRSIsIlAtWCIsICJQLVMiLCAiUC1QIiksIGNvbG9yTGlzdExvb3AsIHNlID0gVFJVRSkKYGBgCiMjIyMjIFB1cmUtcmVnIHZzIHN0ci1yZWcKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX0Fubm8zLnRzdiIpKSkKZGlmZkN1dG9mZiA8LSAwLjIKCiMgU3BsaXR0aW5nIGRhdGEKZGF0YS5yZWcgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMyA9PSAicmVnIikKZGF0YS5zdHIgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMyA9PSAic3RyIikKCiMgVGFraW5nIGNvZGVzIGZyb20gcHJldmlvdXMgZnVuY3Rpb24gKHN0cikKZGF0YSA8LSBkYXRhLnN0cgpkYXRhIDwtIGRhdGEgJT4lCiAgZHBseXI6Om11dGF0ZSh1cGRvd25fZFRBR19ETVNPID0gaWZlbHNlKGRpZmZfZFRBR19ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkaWZmX2RUQUdfRE1TTyA+IC1kaWZmQ3V0b2ZmLCAiTk8iLCAiRE9XTiIpKSwKICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZfQTQ4NV9ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpKQpkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQpkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQoKbnVtLnVwIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJVUCJdCm51bS5ubyA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9kVEFHX0RNU08pKVsiTk8iXQpudW0uZG93biA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9kVEFHX0RNU08pKVsiRE9XTiJdCm51bS5hbGwgPC0gbnVtLnVwICsgbnVtLm5vICsgbnVtLmRvd24KcGVyYy51cCA8LSByb3VuZChudW0udXAgLyBudW0uYWxsICogMTAwLCAyKQpwZXJjLm5vIDwtIHJvdW5kKG51bS5ubyAvIG51bS5hbGwgKiAxMDAsIDIpCnBlcmMuZG93biA8LSByb3VuZChudW0uZG93biAvIG51bS5hbGwgKiAxMDAsIDIpCgpkYXRhJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoZGF0YSRETVNPLCBkYXRhJGRUQUcsIG4gPSAxMDApCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKcDEgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gRE1TTywgeSA9IGRUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlMCgiVVA6ICIsIG51bS51cCwgIiAoIiwgcGVyYy51cCwgIiUpIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLTAuMSwgbGFiZWwgPSBwYXN0ZTAoIk5POiAiLCBudW0ubm8sICIgKCIsIHBlcmMubm8sICIlKSIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMS0wLjIsIGxhYmVsID0gcGFzdGUwKCJET1dOOiAiLCBudW0uZG93biwgIiAoIiwgcGVyYy5kb3duLCAiJSkiKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShuYW1lKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpKQoKIyBUYWtpbmcgY29kZXMgZnJvbSBwcmV2aW91cyBmdW5jdGlvbiAocmVnKQpkYXRhIDwtIGRhdGEucmVnCmRhdGEgPC0gZGF0YSAlPiUKICBkcGx5cjo6bXV0YXRlKHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZfZFRBR19ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpLAogICAgICAgICAgICAgICAgdXBkb3duX0E0ODVfRE1TTyA9IGlmZWxzZShkaWZmX0E0ODVfRE1TTyA+IGRpZmZDdXRvZmYsICJVUCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSkpCmRhdGEkdXBkb3duX2RUQUdfRE1TTyA8LSBmYWN0b3IoZGF0YSR1cGRvd25fZFRBR19ETVNPLCBsZXZlbHMgPSBjKCJVUCIsICJOTyIsICJET1dOIikpCmRhdGEkdXBkb3duX0E0ODVfRE1TTyA8LSBmYWN0b3IoZGF0YSR1cGRvd25fQTQ4NV9ETVNPLCBsZXZlbHMgPSBjKCJVUCIsICJOTyIsICJET1dOIikpCgpudW0udXAgPC0gKHN1bW1hcnkoZGF0YSR1cGRvd25fZFRBR19ETVNPKSlbIlVQIl0KbnVtLm5vIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJOTyJdCm51bS5kb3duIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJET1dOIl0KbnVtLmFsbCA8LSBudW0udXAgKyBudW0ubm8gKyBudW0uZG93bgpwZXJjLnVwIDwtIHJvdW5kKG51bS51cCAvIG51bS5hbGwgKiAxMDAsIDIpCnBlcmMubm8gPC0gcm91bmQobnVtLm5vIC8gbnVtLmFsbCAqIDEwMCwgMikKcGVyYy5kb3duIDwtIHJvdW5kKG51bS5kb3duIC8gbnVtLmFsbCAqIDEwMCwgMikKCmRhdGEkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShkYXRhJERNU08sIGRhdGEkZFRBRywgbiA9IDEwMCkKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpwMiA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBETVNPLCB5ID0gZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUwKCJVUDogIiwgbnVtLnVwLCAiICgiLCBwZXJjLnVwLCAiJSkiKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEtMC4xLCBsYWJlbCA9IHBhc3RlMCgiTk86ICIsIG51bS5ubywgIiAoIiwgcGVyYy5ubywgIiUpIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLTAuMiwgbGFiZWwgPSBwYXN0ZTAoIkRPV046ICIsIG51bS5kb3duLCAiICgiLCBwZXJjLmRvd24sICIlKSIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKG5hbWUpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNSkpICAKICAKCmZpbGVOYW1lIDwtIHBhc3RlMCgic2NhdHRlcnBsb3RfIiwgbmFtZSwgIl8iLCBkaWZmQ3V0b2ZmLCAiX3B1cmVfc3RyX3JlZyIpCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNSoxLjUsIGhlaWdodCA9IDIuNSoxLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKZGV2Lm9mZigpCgpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICB3aWR0aCA9IDUqMS41LCBoZWlnaHQgPSAyLjUqMS41KQpwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCmRldi5vZmYoKQpgYGAKIyMjIyMgNTBrYiB2cyAyMDAga2IKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX0Fubm8zLnRzdiIpKSkKCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShzaXplID0gc3RhcnQyIC0gc3RhcnQxKQoKZGF0YV91bmRlcjUwa2IgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIHNpemUgPCA1MCoxMDAwLCBBbm5vMyA9PSAicmVnIikKZGF0YV91bmRlcjIwMGtiIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBzaXplID49IDUwKjEwMDAsIHNpemUgPCAyMDAqMTAwMCwgQW5ubzMgPT0gInJlZyIpCmRhdGFfb3ZlcjIwMGtiIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBzaXplID49IDIwMCoxMDAwLCBBbm5vMyA9PSAicmVnIikKCiMjIyMjIyMjCgpkYXRhIDwtIGRhdGFfdW5kZXI1MGtiCgpkaWZmQ3V0b2ZmIDwtIDAuMgpkYXRhIDwtIGRhdGEgJT4lCiAgZHBseXI6Om11dGF0ZSh1cGRvd25fZFRBR19ETVNPID0gaWZlbHNlKGRpZmZfZFRBR19ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkaWZmX2RUQUdfRE1TTyA+IC1kaWZmQ3V0b2ZmLCAiTk8iLCAiRE9XTiIpKSwKICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZfQTQ4NV9ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpKQpkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQpkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQoKIyMjIwpudW0udXAgPC0gKHN1bW1hcnkoZGF0YSR1cGRvd25fZFRBR19ETVNPKSlbIlVQIl0KbnVtLm5vIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJOTyJdCm51bS5kb3duIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJET1dOIl0KbnVtLmFsbCA8LSBudW0udXAgKyBudW0ubm8gKyBudW0uZG93bgpwZXJjLnVwIDwtIHJvdW5kKG51bS51cCAvIG51bS5hbGwgKiAxMDAsIDIpCnBlcmMubm8gPC0gcm91bmQobnVtLm5vIC8gbnVtLmFsbCAqIDEwMCwgMikKcGVyYy5kb3duIDwtIHJvdW5kKG51bS5kb3duIC8gbnVtLmFsbCAqIDEwMCwgMikKCmRhdGEkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShkYXRhJERNU08sIGRhdGEkZFRBRywgbiA9IDEwMCkKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpwMSA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBETVNPLCB5ID0gZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHhsaW0oLTAuNSwgMSkgKyB5bGltKC0wLjUsIDEpICsgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEsIGxhYmVsID0gcGFzdGUwKCJVUDogIiwgbnVtLnVwLCAiICgiLCBwZXJjLnVwLCAiJSkiKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTAuNSwgeSA9IDEtMC4xLCBsYWJlbCA9IHBhc3RlMCgiTk86ICIsIG51bS5ubywgIiAoIiwgcGVyYy5ubywgIiUpIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLTAuMiwgbGFiZWwgPSBwYXN0ZTAoIkRPV046ICIsIG51bS5kb3duLCAiICgiLCBwZXJjLmRvd24sICIlKSIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKG5hbWUpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNSkpICAKICAKCiMjIyMKbnVtLnVwIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX0E0ODVfRE1TTykpWyJVUCJdCm51bS5ubyA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9BNDg1X0RNU08pKVsiTk8iXQpudW0uZG93biA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9BNDg1X0RNU08pKVsiRE9XTiJdCm51bS5hbGwgPC0gbnVtLnVwICsgbnVtLm5vICsgbnVtLmRvd24KcGVyYy51cCA8LSByb3VuZChudW0udXAgLyBudW0uYWxsICogMTAwLCAyKQpwZXJjLm5vIDwtIHJvdW5kKG51bS5ubyAvIG51bS5hbGwgKiAxMDAsIDIpCnBlcmMuZG93biA8LSByb3VuZChudW0uZG93biAvIG51bS5hbGwgKiAxMDAsIDIpCgpkYXRhJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoZGF0YSRETVNPLCBkYXRhJEE0ODUsIG4gPSAxMDApCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKcDIgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gRE1TTywgeSA9IEE0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICB4bGltKC0wLjUsIDEpICsgeWxpbSgtMC41LCAxKSArIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLCBsYWJlbCA9IHBhc3RlMCgiVVA6ICIsIG51bS51cCwgIiAoIiwgcGVyYy51cCwgIiUpIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjUsIHkgPSAxLTAuMSwgbGFiZWwgPSBwYXN0ZTAoIk5POiAiLCBudW0ubm8sICIgKCIsIHBlcmMubm8sICIlKSIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMC41LCB5ID0gMS0wLjIsIGxhYmVsID0gcGFzdGUwKCJET1dOOiAiLCBudW0uZG93biwgIiAoIiwgcGVyYy5kb3duLCAiJSkiKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShuYW1lKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpKSAgCiAgCgpmaWxlTmFtZSA8LSBwYXN0ZTAoInNjYXR0ZXJwbG90XyIsIG5hbWUsICJfIiwgZGlmZkN1dG9mZiwgIl9yZWd1bmRlcjUwa2JfcHVyZSIpCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNSoxLjUsIGhlaWdodCA9IDIuNSoxLjUpCnByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKZGV2Lm9mZigpCgpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICB3aWR0aCA9IDUqMS41LCBoZWlnaHQgPSAyLjUqMS41KQpwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCmRldi5vZmYoKQoKYGBgCgojIyMjIE9uZSBmZWF0dXJlIGFubm90YXRpb24gLSBwcm9tb3RlcgpgYGB7cn0KCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9Qcm9tb3RlciIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgImFsbCIpLCB1bmlxdWUoZGF0YSRBbm5vMikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAicC1wIiksIGMoIlAtUCIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgInAtbiIpLCBjKCJQLU4iKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJuLW4iKSwgYygiTi1OIikpCgpjb2xvckxpc3QgPC0gY29sb3JMaXN0UHJvbW90ZXIKbG9vcExpc3QgPC0gYygiTi1OIiwgIlAtTiIsICJQLVAiKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfRE1TTyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QsIHNlID0gVFJVRSkKY3JlYXRlX3Njb3JlX2JhcnBsb3RfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfRE1TTyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0KQp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkVEFHLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQoKY3JlYXRlX3Njb3JlX2JhcnBsb3RfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfZFRBRyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0KQp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBBNDg1LCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQpjcmVhdGVfc2NvcmVfYmFycGxvdF9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkaWZmX2RUQUdfRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnRGlmZlNjb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2RUQUciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IFRSVUUpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkaWZmX0E0ODVfRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnRGlmZlNjb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IFRSVUUpCmBgYAoKIyMjIyBPbmUgZmVhdHVyZSBhbm5vdGF0aW9uIC0gZW5oYW5jZXIKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9FbmhhbmNlciIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgImFsbCIpLCB1bmlxdWUoZGF0YSRBbm5vMikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAiZS1lIiksIGMoIkUtRSIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgImUtbiIpLCBjKCJFLU4iKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJuLW4iKSwgYygiTi1OIikpCgpjb2xvckxpc3QgPC0gY29sb3JMaXN0RW5oYW5jZXIKbG9vcExpc3QgPC0gYygiTi1OIiwgIkUtTiIsICJFLUUiKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfRE1TTyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QsIHNlID0gVFJVRSkKY3JlYXRlX3Njb3JlX2JhcnBsb3RfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfRE1TTyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0KQp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBkVEFHLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQpjcmVhdGVfc2NvcmVfYmFycGxvdF9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QpCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIEE0ODUsIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z1Njb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IFRSVUUpCmNyZWF0ZV9zY29yZV9iYXJwbG90X3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCkKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGRpZmZfZFRBR19ETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdEaWZmU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfZFRBRyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QsIHNlID0gVFJVRSkKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGRpZmZfQTQ4NV9ETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdEaWZmU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfQTQ4NSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QsIHNlID0gVFJVRSkKYGBgCiMjIyMgT25lIGZlYXR1cmUgYW5ub3RhdGlvbiAtIHN0cnVjdHVyZQoKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9TdHJ1Y3R1cmUiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJhbGwiKSwgdW5pcXVlKGRhdGEkQW5ubzIpKQppdGVyYXRlX2xvb3BfZnVuY3Rpb25zKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfIiwgInMtcyIpLCBjKCJTLVMiKSkKaXRlcmF0ZV9sb29wX2Z1bmN0aW9ucyhkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiXyIsICJzLW4iKSwgYygiUy1OIikpCml0ZXJhdGVfbG9vcF9mdW5jdGlvbnMoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl8iLCAibi1uIiksIGMoIk4tTiIpKQoKY29sb3JMaXN0IDwtIGNvbG9yTGlzdFN0cnVjdHVyZQpsb29wTGlzdCA8LSBjKCJOLU4iLCAiUy1OIiwgIlMtUyIpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9ETVNPIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQpjcmVhdGVfc2NvcmVfYmFycGxvdF9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9ETVNPIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QpCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGRUQUcsIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z1Njb3JlX3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2RUQUciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IFRSVUUpCmNyZWF0ZV9zY29yZV9iYXJwbG90X3BlclRyZWF0bWVudCh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2RUQUciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCkKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgQTQ4NSwgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfQTQ4NSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BMaXN0LCBjb2xvckxpc3QsIHNlID0gVFJVRSkKY3JlYXRlX3Njb3JlX2JhcnBsb3RfcGVyVHJlYXRtZW50KHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfQTQ4NSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wTGlzdCwgY29sb3JMaXN0KQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgZGlmZl9kVEFHX0RNU08sIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgZGlmZl9BNDg1X0RNU08sIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnQodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcExpc3QsIGNvbG9yTGlzdCwgc2UgPSBUUlVFKQoKYGBgCgojIyMgWzIuN10gRGlzdGFuY2UgdnMgbG9vcCAjIGFuZCBzY29yZQpgYGB7cn0KZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX3Njb3JlLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcmVzID0gZW5kMSAtIHN0YXJ0MSkKCnAxIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGRpc3RhbmNlLCBmaWxsID0gZmFjdG9yKHJlcykpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1MDAwMCwgYWxwaGEgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRGlzdGFuY2UgYnkgUmVzb2x1dGlvbiIsCiAgICAgICB4ID0gIkRpc3RhbmNlIiwKICAgICAgIHkgPSAiQ291bnRzIikgKyAKICBmYWNldF93cmFwKH4gcmVzLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWUiKSArIAogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYiwgbGltaXRzID0gYygwLCA1ZTYpKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSAgIyBSZW1vdmVzIHRoZSBsZWdlbmQKCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKCJjb25zZW5zdXNfZGlzdF9wZXJfcmVzLnBuZyIpKSwgCiAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAzLCBoZWlnaHQgPSA2KQpwcmludChwMSkKZGV2Lm9mZigpCgpwMiA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBkaXN0YW5jZSwgZmlsbCA9IGZhY3RvcihyZXMpKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNTAwMDAsIGFscGhhID0gMSkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIERpc3RhbmNlIGJ5IFJlc29sdXRpb24iLAogICAgICAgeCA9ICJEaXN0YW5jZSIsCiAgICAgICB5ID0gIkNvdW50cyIpICsgCiAgZmFjZXRfd3JhcCh+IHJlcywgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIsIGxpbWl0cyA9IGMoMCwgMmU2KSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgICMgUmVtb3ZlcyB0aGUgbGVnZW5kCgoKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoImNvbnNlbnN1c19kaXN0X3Blcl9yZXNfMm1iLnBuZyIpKSwgCiAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAzLCBoZWlnaHQgPSA2KQpwcmludChwMikKZGV2Lm9mZigpCgoKYGBgCgoKYGBge3J9CiMjIyBEaXN0YW5jZSB2cyBzY29yZQogIAogIHRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIERNU08sIGRUQUcsIEE0ODUpCiAgCiAgYXZnX3Njb3JlcyA8LSB0ZW1wICU+JQogICAgZ3JvdXBfYnkoZGlzdGFuY2UpICU+JQogICAgc3VtbWFyaXNlKGFjcm9zcyhzdGFydHNfd2l0aCgiRE1TTyIpOnN0YXJ0c193aXRoKCJBNDg1IiksIG1lYW4sIG5hLnJtID0gVFJVRSkpCiAgCiAgYXZnX3Njb3Jlc19sb25nIDwtIGF2Z19zY29yZXMgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IERNU086QTQ4NSwgbmFtZXNfdG8gPSAiY29uZGl0aW9uIiwgdmFsdWVzX3RvID0gImF2Z19zY29yZSIpCiAgYXZnX3Njb3Jlc19sb25nJGNvbmRpdGlvbiA8LSBmYWN0b3IoYXZnX3Njb3Jlc19sb25nJGNvbmRpdGlvbiwgbGV2ZWxzID0gYygiRE1TTyIsICJkVEFHIiwgIkE0ODUiKSkKICAjIENyZWF0ZSB0aGUgcGxvdAogIHA0IDwtIGdncGxvdChhdmdfc2NvcmVzX2xvbmcsIGFlcyh4ID0gZGlzdGFuY2UsIHkgPSBhdmdfc2NvcmUsIGNvbG9yID0gY29uZGl0aW9uLCBmaWxsID0gY29uZGl0aW9uKSkgKwogICAgZ2VvbV9zbW9vdGgoc2hvdy5sZWdlbmQgPSBUUlVFKSArIHlsaW0oMCwgMC41KSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiRE1TTyIgPSAiZ3JleSIsICJkVEFHIiA9ICJwaW5rIiwgIkE0ODUiID0gInNreWJsdWUiKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRE1TTyIgPSAiZ3JleTgwIiwgImRUQUciID0gInBpbmsiLCAiQTQ4NSIgPSAic2t5Ymx1ZSIpKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKCJEaXN0YW5jZSB2cy4gQXZlcmFnZSBTY29yZSwgIiwgbm90ZSksCiAgICAgICAgIHggPSAiRGlzdGFuY2UiLAogICAgICAgICB5ID0gIkF2ZXJhZ2UgU2NvcmUiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoImNvbnNlbnN1c19kaXN0X3ZzX2F2Z1Njb3JlX2FsbFJlc19wdTEwMHB6MTAwXyIsIG5vdGUsICIucG5nIikpLCAKICAgICAgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMykKICBwcmludChwNCkKICBkZXYub2ZmKCkKCmBgYAoKIyMjIFsyLjhdIEFubm90YXRpbmcgZ2VuZXMgdG8gUC1QIGFuZCBQLUUgbG9vcHMKIyMjIyBMaW5rIGdlbmUgdG8gcHJvbW90ZXIgYW5jaG9yCkhlcmUsIGFuY2hvciB3YXMgbGlua2VkIHRvIGEgZ2VuZSBiYXNlZCBvbiB3aGV0aGVyIHRoZSBhbmNob3Igb3ZlcmxhcHMgd2l0aCBUU1MgKy0gMi41a2IgcmVnaW9uCmBgYHtyfQojIEFubm90YXRpbmcgZ2VuZXMgYmFzZWQgb24gcHJvbW90ZXIgYW5jaG9yCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKYGBgCgoKYGBge3J9CmZsYW5rU2l6ZSA8LSAyNTAwCmdlbmUuVFNTLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNCwgVjUsIFY2KQpjb2xuYW1lcyhnZW5lLlRTUy50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJzdHJhbmQiLCAiZ2VuZSIsICJlbnNlbWJsIikKCmZ3cml0ZShnZW5lLlRTUy50YiwgaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9UU1MyLjVrYi5iZWQiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFKQoKZmluZE92ZXJsYXBHZW5lIDwtIGZ1bmN0aW9uKGdlbmUuVFNTLnRiLCBjaHJvbTEsIHN0YXJ0MSwgZW5kMSl7CiAgdGVtcCA8LSBnZW5lLlRTUy50YiAlPiUgZHBseXI6OmZpbHRlcihjaHIgPT0gY2hyb20xKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoKHN0YXJ0IDw9IGVuZDEpICYgKGVuZCA+PSBzdGFydDEpKQogIHJldHVybih0ZW1wJGdlbmUpCn0KZmluZE92ZXJsYXBFbnNlbWJsIDwtIGZ1bmN0aW9uKGdlbmUuVFNTLnRiLCBjaHJvbTEsIHN0YXJ0MSwgZW5kMSl7CiAgdGVtcCA8LSBnZW5lLlRTUy50YiAlPiUgZHBseXI6OmZpbHRlcihjaHIgPT0gY2hyb20xKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoKHN0YXJ0IDw9IGVuZDEpICYgKGVuZCA+PSBzdGFydDEpKQogIHJldHVybih0ZW1wJGVuc2VtYmwpCn0KCnRlbXAgPC0gZGF0YSAlPiUgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUoQTFfZ2VuZSA9IGlmZWxzZShBMSA9PSAiUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QoZmluZE92ZXJsYXBHZW5lKGdlbmUuVFNTLnRiLCBjaHJvbTEsIHN0YXJ0MSwgZW5kMSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSksCiAgICAgICAgICAgICAgICBBMl9nZW5lID0gaWZlbHNlKEEyID09ICJQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChmaW5kT3ZlcmxhcEdlbmUoZ2VuZS5UU1MudGIsIGNocm9tMiwgc3RhcnQyLCBlbmQyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BKSwKICAgICAgICAgICAgICAgIGdlbmUgPSBsaXN0KHVuaXF1ZShjKEExX2dlbmUsIEEyX2dlbmUpKSkpCgp0ZW1wX3BfbiA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpICU+JSBkcGx5cjo6c2VsZWN0KC1jKCJBMV9nZW5lIiwgIkEyX2dlbmUiKSkKZndyaXRlKHRlbXBfcF9uLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2dlbmVMaXN0LnRzdiIpKSwgc2VwID0gIlx0IikKCnRlbXBfcF9wZSA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIpKSAlPiUgZHBseXI6OnNlbGVjdCgtYygiQTFfZ2VuZSIsICJBMl9nZW5lIikpCmZ3cml0ZSh0ZW1wX3BfcGUsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLXBlX2dlbmVMaXN0LnRzdiIpKSwgc2VwID0gIlx0IikKCnRlbXAgPC0gZGF0YSAlPiUgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUoQTFfZ2VuZSA9IGlmZWxzZShBMSA9PSAiUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QoZmluZE92ZXJsYXBFbnNlbWJsKGdlbmUuVFNTLnRiLCBjaHJvbTEsIHN0YXJ0MSwgZW5kMSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSksCiAgICAgICAgICAgICAgICBBMl9nZW5lID0gaWZlbHNlKEEyID09ICJQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChmaW5kT3ZlcmxhcEVuc2VtYmwoZ2VuZS5UU1MudGIsIGNocm9tMiwgc3RhcnQyLCBlbmQyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BKSwKICAgICAgICAgICAgICAgIGdlbmUgPSBsaXN0KHVuaXF1ZShjKEExX2dlbmUsIEEyX2dlbmUpKSkpCgp0ZW1wX3BfbiA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpICU+JSBkcGx5cjo6c2VsZWN0KC1jKCJBMV9nZW5lIiwgIkEyX2dlbmUiKSkKZndyaXRlKHRlbXBfcF9uLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwgc2VwID0gIlx0IikKCnRlbXBfcF9wZSA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIpKSAlPiUgZHBseXI6OnNlbGVjdCgtYygiQTFfZ2VuZSIsICJBMl9nZW5lIikpCmZ3cml0ZSh0ZW1wX3BfcGUsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLXBlX2Vuc2VtYmxMaXN0LnRzdiIpKSwgc2VwID0gIlx0IikKCmBgYAojIyMgWzIuOV0gU2l6ZSBkaXN0cmlidXRpb24gb2YgZGlmZiBsb29wcwoKYGBge3J9CmNyZWF0ZV9kaXN0X2JhcnBsb3QgPC0gZnVuY3Rpb24oZGF0YSwgZmlnRGlyLCBuYW1lLCBub3RlLCBsb29wTGlzdCwgZGlmZkN1dG9mZil7CiAgdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KEFubm8yLCBkaXN0YW5jZSwgdXBkb3duX2RUQUdfRE1TTywgdXBkb3duX0E0ODVfRE1TTykgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgbG9vcExpc3QsCiAgICAgICAgICAgICAgICAgIHVwZG93bl9kVEFHX0RNU08gJWluJSBjKCJVUCIsICJOTyIsICJET1dOIikpCiAgcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSB1cGRvd25fZFRBR19ETVNPLCB5ID0gZGlzdGFuY2UpKSArCiAgICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHVwZG93bl9kVEFHX0RNU08pKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSB1cGRvd25fZFRBR19ETVNPKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShub3RlKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJzaXplX2JhcnBsb3RfIiwgbmFtZSwgIl9kVEFHX3ZzX0RNU09fIiwgbm90ZSwgIl8iLCBkaWZmQ3V0b2ZmKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gNAogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIAogIAogIHRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChBbm5vMiwgZGlzdGFuY2UsIHVwZG93bl9kVEFHX0RNU08sIHVwZG93bl9BNDg1X0RNU08pICU+JQogICAgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGxvb3BMaXN0LAogICAgICAgICAgICAgICAgICB1cGRvd25fQTQ4NV9ETVNPICVpbiUgYygiVVAiLCAiTk8iLCAgIkRPV04iKSkKICBwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHVwZG93bl9BNDg1X0RNU08sIHkgPSBkaXN0YW5jZSkpICsKICAgIGdlb21fdmlvbGluKGFlcyhmaWxsID0gdXBkb3duX0E0ODVfRE1TTykpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHVwZG93bl9BNDg1X0RNU08pLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBnZ3RpdGxlKG5vdGUpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNpemVfYmFycGxvdF8iLCBuYW1lLCAiX0E0ODVfdnNfRE1TT18iLCBub3RlLCAiXyIsIGRpZmZDdXRvZmYpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSA0CiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCgpuYW1lCmRpZmZDdXRvZmYgPC0gMC4yCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKZGF0YSA8LSBkYXRhICU+JQogIGRwbHlyOjptdXRhdGUodXBkb3duX2RUQUdfRE1TTyA9IGlmZWxzZShkaWZmX2RUQUdfRE1TTyA+IGRpZmZDdXRvZmYsICJVUCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICB1cGRvd25fQTQ4NV9ETVNPID0gaWZlbHNlKGRpZmZfQTQ4NV9ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkaWZmX0E0ODVfRE1TTyA+IC1kaWZmQ3V0b2ZmLCAiTk8iLCAiRE9XTiIpKSwKICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKQpkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQpkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQpjcmVhdGVfZGlzdF9iYXJwbG90KGRhdGEsIGZpZ0RpciwgbmFtZSwgInAtbiIsIGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpLCAwLjIpCmNyZWF0ZV9kaXN0X2JhcnBsb3QoZGF0YSwgZmlnRGlyLCBuYW1lLCAicC1wZSIsIGMoIlAtUCIsICJQLUUiKSwgMC4yKQpjcmVhdGVfZGlzdF9iYXJwbG90KGRhdGEsIGZpZ0RpciwgbmFtZSwgInBlLXBlIiwgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgMC4yKQpjcmVhdGVfZGlzdF9iYXJwbG90KGRhdGEsIGZpZ0RpciwgbmFtZSwgInN0ciIsIGMoIlMtUyIsICJTLVgiKSwgMC4yKQoKYGBgCiMjIyBbMi4xMF0gTGlua2luZyB3aXRoIFJOQS1zZXEvUFJPLXNlcQojIyMjIEZ1bmN0aW9uICYgcGFyYW1ldGVyCmBgYHtyfQpHT2RpciA8LSBoZXJlKCIuLi8uLiIsICJyZXN1bHQiLCAibG9vcCIsICJHTyIpCmRpci5jcmVhdGUoR09kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQoKZ2V0R08gPC0gZnVuY3Rpb24obmFtZSwgZmlnRGlyLCBnZW5lTGlzdCwgY2F0ZWdvcnlOdW0gPSAxNSwgaGVpZ2h0ID0gMTAsIHdpZHRoID0gNyl7CiAgR08gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKICBHTy5yZWFkYWJsZSA8LSBzZXRSZWFkYWJsZShHTywgT3JnRGIgPSBvcmcuTW0uZWcuZGIpCiAgZndyaXRlKGFzLmRhdGEuZnJhbWUoR08pLCBoZXJlKEdPZGlyLCBwYXN0ZTAoIkdPXyIsIG5hbWUsICJfZW5zZW1ibC50c3YiKSksIHNlcCA9ICJcdCIpCiAgZndyaXRlKGFzLmRhdGEuZnJhbWUoR08ucmVhZGFibGUpLCBoZXJlKEdPZGlyLCBwYXN0ZTAoIkdPXyIsIG5hbWUsICJfcmVhZGFibGUudHN2IikpLCBzZXAgPSAiXHQiKQogIAogIGlmKG5yb3coYXMuZGF0YS5mcmFtZShHTykpICE9IDApewogICAgIyMjIyMKICAgIGZpbGVOYW1lIDwtIHBhc3RlMCgiR09fIiwgbmFtZSkKICAgIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICAgIHByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IGNhdGVnb3J5TnVtLCB0aXRsZSA9IG5hbWUpICsgCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKICAgIGRldi5vZmYoKQogICAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgsIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIpCiAgICBwcmludChkb3RwbG90KEdPLCBzaG93Q2F0ZWdvcnkgPSBjYXRlZ29yeU51bSwgdGl0bGUgPSBuYW1lKSArIAogICAgICAgICAgICBzY2FsZV9jb2xvcl9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMC4wNSksIGxvdyA9ICJyZWQiLCBoaWdoID0gImJsYWNrIikpCiAgICBkZXYub2ZmKCkKICB9IAp9Cgpjb252UHZhbHVlIDwtIGZ1bmN0aW9uKHB2YWx1ZSl7CiAgb3V0IDwtIGlmZWxzZShwdmFsdWUgPCAwLjAwMDEsICIqKioqIiwKICAgICAgICAgICAgICAgIGlmZWxzZShwdmFsdWUgPCAwLjAwMSwgIioqKiIsCiAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHB2YWx1ZSA8IDAuMDEsICIqKiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwdmFsdWUgPCAwLjA1LCAiKiIsICJucyIpKSkpCiAgcmV0dXJuKG91dCkKfQoKbG9hZExvb3BBbm5vRGF0YSA8LSBmdW5jdGlvbihmaWxlTmFtZSwgZGlmZkN1dG9mZiA9IDAuMiwgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSl7CiAgZGF0YSA8LSBmcmVhZChmaWxlTmFtZSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIGdlbmUgPSBzdHJzcGxpdChnZW5lLCAnXFx8JykpICU+JQogICAgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lICBhbm5vTGlzdCkKICBkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIGRhdGEkdXBkb3duX0E0ODVfRE1TTyA8LSBmYWN0b3IoZGF0YSR1cGRvd25fQTQ4NV9ETVNPLCBsZXZlbHMgPSBjKCJVUCIsICJOTyIsICJET1dOIikpCiAgCiAgcmV0dXJuKGRhdGEpCn0KYGBgCgojIyMjIGRUQUcgU2NhdHRlcnBsb3QKYGBge3J9Cmxvb3BUeXBlIDwtICJwLW4iCgojIGdldHRpbmcgbGlzdCBvZiBnZW5lcyBvZiBpbnRlcmVzdCBmcm9tIFJOQS1zZXEgYW5kIFBSTy1zZXEKYWxwaGEgPC0gMC4wNQpmY0N1dG9mZiA8LSAwLjUKZGlmZi5QUk8uRzEuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzFHMi5kVEFHX0cxLmRUQUdfdnNfRzEuRE1TT19QUk9zZXEudHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlBSTy5HMi5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMUcyLmRUQUdfRzIuZFRBR192c19HMi5ETVNPX1BST3NlcS50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUk5BLkcxLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEpCiMgSW1wb3J0aW5nIGxvb3AgZ2VuZSBhbm5vdGF0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpkaWZmQ3V0b2ZmIDwtIDAuMgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gZGlmZkN1dG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JQogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpCiMgZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gZGlmZkN1dG9mZiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIikpJT4lIAojICAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKIyBUZXN0aW5nIGRpZmZlcmVudCB3YXlzIHRvIGNhbGN1bGF0ZSByZXByZXNlbnRhdGl2ZSBmZWF0dXJlIG9mIGxvb3BzIGZvciBlYWNoIGdlbmUKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQpnZW5lTGlzdC5kb3duIDwtIHVuaXF1ZShjKChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAoZGlmZi5QUk8uRzIuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkKSkKZ2VuZUxpc3QuZG93bi5STkEgPC0gKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZApnZW5lTGlzdC5kb3duLlJOQS5ub0ZDY3V0b2ZmIDwtIChkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZApnZW5lTGlzdC51cGRvd24uUk5BLm5vRkNjdXRvZmYgPC0gKGRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZikkZW5zZW1ibF9nZW5lX2lkCgpnZW5lTGlzdC51cCA8LSB1bmlxdWUoYygoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPiAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAoZGlmZi5QUk8uRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPiAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAoZGlmZi5QUk8uRzIuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPiAwKSkkZW5zZW1ibF9nZW5lX2lkKSkKCgojIFsxXSBBdmVyYWdlIG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSAyCgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX2RUQUdfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9kVEFHX0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCiNmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJnZW5lX2F2Z1Njb3JlX2ZjX2RUQUdfcC1uLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyAKIyBwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKIyAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiMgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwojICAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKIyAgIGdndGl0bGUoImRUQUciKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJncmV5IiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKIyAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCiMgCiMgZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfYXZnU2NvcmVfZFRBR18iLCBsb29wVHlwZSwgIl9kaWZmQ3V0b2ZmXyIsIGRpZmZDdXRvZmYpCiMgaGVpZ2h0IDwtIDQKIyB3aWR0aCA8LSA3CiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKIyBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCgojIE5vIEZDIGN1dG9mZiBvcHRpb24gLSBkb3duIG9ubHkKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9kVEFHX0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfZFRBR19ETVNPKSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQS5ub0ZDY3V0b2ZmLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCiMgZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImdlbmVfYXZnU2NvcmVfZmNfZFRBR18iLCBsb29wVHlwZSwgIl9ub0ZDY3V0b2ZmLnRzdiIpKSwgc2VwID0gIlx0IikKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2hyaW5rZWRfbG9nMkZDLCB5ID0gbWVhbl9kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLCBhbHBoYSA9IDEsCiAgICAgIHN0cm9rZSA9IDApICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBndWlkZXMoY29sb3IgPSAibm9uZSIsIHNoYXBlID0gIm5vbmUiKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYyhkaWZmQ3V0b2ZmLCAtZGlmZkN1dG9mZiksIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhID0gMSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAxLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKGZjQ3V0b2ZmLCAtZmNDdXRvZmYpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDEsCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLCAgICAKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgKyBsYWJzKHkgPSAiQXZnLiDOlCBsb29wIHNjb3JlIiwgeCA9ICJsb2cyKHNocnVua2VuIEZDKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICIjQTlBOEE5IiwgIjFVUCIgPSAiI0NCMzMzQSIsICIyRE9XTiIgPSAiIzQ4NTJBMCIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX2F2Z1Njb3JlX2RUQUdfIiwgbG9vcFR5cGUsICJfZGlmZkN1dG9mZl8iLCBkaWZmQ3V0b2ZmLCAiX25vRkNjdXRvZmYiKQpoZWlnaHQgPC0gNDIqbW1Ub0luY2gKd2lkdGggPC0gNTAqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCiMgTm8gRkMgY3V0b2ZmIG9wdGlvbiAtIHVwIGFuZCBkb3duCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfZFRBR19ETVNPLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX2RUQUdfRE1TTyksIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QudXBkb3duLlJOQS5ub0ZDY3V0b2ZmLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmlua2VkX2xvZzJGQywgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHXyIsIGxvb3BUeXBlLCAiX2RpZmZDdXRvZmZfIiwgZGlmZkN1dG9mZiwgIl9ub0ZDY3V0b2ZmdXBkb3duIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKIyAKIyAjIyBSTkEgKyBQUk8tc2VxCiMgdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9kVEFHX0RNU08sIGdlbmUpICU+JSAKIyAgIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiMgICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX2RUQUdfRE1TTyksIC5ncm91cHMgPSAnZHJvcCcpCiMgCiMgdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKIyAgIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93biwgIjJET1dOIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LnVwLCAiMVVQIiwgIjBOTyIpKSwKIyAgICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiMgICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiMgICBkcGx5cjo6YXJyYW5nZShmbGFnKQojIAojIGZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR18iLCBsb29wVHlwZSwgIi50c3YiKSwgc2VwID0gIlx0IikKIyAKIyBwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKIyAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiMgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwojICAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKIyAgIGdndGl0bGUoImRUQUciKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJncmV5IiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKIyAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCiMgCiMgZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfYXZnU2NvcmVfZFRBR18iLCBsb29wVHlwZSwgIl9kaWZmQ3V0b2ZmXyIsIGRpZmZDdXRvZmYsICJfUk5BLVBSTyIpCiMgaGVpZ2h0IDwtIDQKIyB3aWR0aCA8LSA3CiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKIyBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCmBgYAoKCiMjIyMgZFRBRyBTY2F0dGVycGxvdCBPRQojIyMjIyBBdmcKYGBge3J9Cgpsb29wVHlwZSA8LSAicC1wZSIKCiMgZ2V0dGluZyBsaXN0IG9mIGdlbmVzIG9mIGludGVyZXN0IGZyb20gUk5BLXNlcSBhbmQgUFJPLXNlcQphbHBoYSA8LSAwLjA1CmZjQ3V0b2ZmIDwtIDAuNQpkaWZmLlBSTy5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMUcyLmRUQUdfRzEuZFRBR192c19HMS5ETVNPX1BST3NlcS50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUFJPLkcyLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMi5kVEFHX3ZzX0cyLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5STkEuRzEuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSkKIyBJbXBvcnRpbmcgbG9vcCBnZW5lIGFubm90YXRpb24KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpCgoKIyBMb2FkaW5nIE9FIGxvb3Agc2NvcmUKbWluVmFsdWUgPC0gLTQKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTywKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPSBsb2dfb2JzZXhwX0E0ODUgLSBsb2dfb2JzZXhwX0RNU08pCgpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSBsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpCgojIFRlc3RpbmcgZGlmZmVyZW50IHdheXMgdG8gY2FsY3VsYXRlIHJlcHJlc2VudGF0aXZlIGZlYXR1cmUgb2YgbG9vcHMgZm9yIGVhY2ggZ2VuZQpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmdlbmVMaXN0LmRvd24gPC0gdW5pcXVlKGMoKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAoZGlmZi5QUk8uRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMi5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQpKQpnZW5lTGlzdC5kb3duLlJOQSA8LSAoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkCmdlbmVMaXN0LmRvd24uUk5BLm5vRkNjdXRvZmYgPC0gKGRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkCmdlbmVMaXN0LnVwZG93bi5STkEubm9GQ2N1dG9mZiA8LSAoZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmKSRlbnNlbWJsX2dlbmVfaWQKCmdlbmVMaXN0LnVwIDwtIHVuaXF1ZShjKChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMi5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQpKQoKCiMgWzFdIEF2ZXJhZ2Ugb2YgZGlmZmVyZW50aWFsIGxvb3Agc2NvcmVzIGZvciBlYWNoIGdlbmUKIyMgUk5BIG9ubHkKZmNDdXRvZmYgPC0gMC41CmFscGhhIDwtIDAuMDUKbWF4TG9nMkZDIDwtIDIKCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCiNmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJnZW5lX2F2Z1Njb3JlX2ZjX2RUQUdfcC1uLnRzdiIpLCBzZXAgPSAiXHQiKQoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJsb2cyZmNNYXgsIHkgPSBtZWFuX2RpZmZfc2NvcmUsIGNvbG9yID0gZmxhZywgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGlmZWxzZShmbGFnICE9ICIwTk8iLCBleHRlcm5hbF9nZW5lX25hbWUsIE5BKSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dF9yZXBlbCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiZFRBRyIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJncmV5IiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAyLCAiRkFMU0UiID0gMTkpKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfYXZnU2NvcmVfZFRBR19PRV8iLCBsb29wVHlwZSwgIl9hdmdMb2dPRSIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCiMgTm8gRkMgY3V0b2ZmIG9wdGlvbiAtIGRvd24gb25seQp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPKSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQS5ub0ZDY3V0b2ZmLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmlua2VkX2xvZzJGQywgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FXyIsIGxvb3BUeXBlLCAiX2F2Z0xvZ09FX25vRkNjdXRvZmYiKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAojIyMjIyBTdW0KYGBge3J9CiMgZ2V0dGluZyBsaXN0IG9mIGdlbmVzIG9mIGludGVyZXN0IGZyb20gUk5BLXNlcSBhbmQgUFJPLXNlcQphbHBoYSA8LSAwLjA1CmZjQ3V0b2ZmIDwtIDAuNQpkaWZmLlBSTy5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMUcyLmRUQUdfRzEuZFRBR192c19HMS5ETVNPX1BST3NlcS50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUFJPLkcyLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMi5kVEFHX3ZzX0cyLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5STkEuRzEuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSkKIyBJbXBvcnRpbmcgbG9vcCBnZW5lIGFubm90YXRpb24KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpCgoKIyBMb2FkaW5nIE9FIGxvb3Agc2NvcmUKbWluVmFsdWUgPC0gLTQKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTywKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPSBsb2dfb2JzZXhwX0E0ODUgLSBsb2dfb2JzZXhwX0RNU08pCgpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSBsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpCgojIFRlc3RpbmcgZGlmZmVyZW50IHdheXMgdG8gY2FsY3VsYXRlIHJlcHJlc2VudGF0aXZlIGZlYXR1cmUgb2YgbG9vcHMgZm9yIGVhY2ggZ2VuZQpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmdlbmVMaXN0LmRvd24gPC0gdW5pcXVlKGMoKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAoZGlmZi5QUk8uRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMi5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQpKQpnZW5lTGlzdC5kb3duLlJOQSA8LSAoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkCmdlbmVMaXN0LmRvd24uUk5BLm5vRkNjdXRvZmYgPC0gKGRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkCmdlbmVMaXN0LnVwZG93bi5STkEubm9GQ2N1dG9mZiA8LSAoZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmKSRlbnNlbWJsX2dlbmVfaWQKCmdlbmVMaXN0LnVwIDwtIHVuaXF1ZShjKChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMi5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IDApKSRlbnNlbWJsX2dlbmVfaWQpKQoKCiMgWzFdIEF2ZXJhZ2Ugb2YgZGlmZmVyZW50aWFsIGxvb3Agc2NvcmVzIGZvciBlYWNoIGdlbmUKIyMgUk5BIG9ubHkKZmNDdXRvZmYgPC0gMC41CmFscGhhIDwtIDAuMDUKbWF4TG9nMkZDIDwtIDIKCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBzdW0obG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyksIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgYygpLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKI2Z3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR19wLW4udHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FX3Atbl9zdW1Mb2dPRSIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCiMgTm8gRkMgY3V0b2ZmIG9wdGlvbiAtIGRvd24gb25seQp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gc3VtKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLm5vRkNjdXRvZmYsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgYygpLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2hyaW5rZWRfbG9nMkZDLCB5ID0gbWVhbl9kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHRfcmVwZWwoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIGdndGl0bGUoImRUQUciKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjBOTyIgPSAiZ3JleSIsICIxVVAiID0gInJlZCIsICIyRE9XTiIgPSAiYmx1ZSIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX2F2Z1Njb3JlX2RUQUdfT0VfcC1uX3N1bUxvZ09FX25vRkNjdXRvZmYiKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgYWJzIG1heApgYGB7cn0KIyBnZXR0aW5nIGxpc3Qgb2YgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSBSTkEtc2VxIGFuZCBQUk8tc2VxCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CmRpZmYuUFJPLkcxLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMS5kVEFHX3ZzX0cxLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5QUk8uRzIuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzFHMi5kVEFHX0cyLmRUQUdfdnNfRzIuRE1TT19QUk9zZXEudHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhKQojIEltcG9ydGluZyBsb29wIGdlbmUgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSklPiUgCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKCgojIExvYWRpbmcgT0UgbG9vcCBzY29yZQptaW5WYWx1ZSA8LSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID0gbG9nX29ic2V4cF9kVEFHIC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA9IGxvZ19vYnNleHBfQTQ4NSAtIGxvZ19vYnNleHBfRE1TTykKCmdlbmVBbm5vRGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkKCiMgVGVzdGluZyBkaWZmZXJlbnQgd2F5cyB0byBjYWxjdWxhdGUgcmVwcmVzZW50YXRpdmUgZmVhdHVyZSBvZiBsb29wcyBmb3IgZWFjaCBnZW5lCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKZ2VuZUxpc3QuZG93biA8LSB1bmlxdWUoYygoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCmdlbmVMaXN0LmRvd24uUk5BIDwtIChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QuZG93bi5STkEubm9GQ2N1dG9mZiA8LSAoZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QudXBkb3duLlJOQS5ub0ZDY3V0b2ZmIDwtIChkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYpJGVuc2VtYmxfZ2VuZV9pZAoKZ2VuZUxpc3QudXAgPC0gdW5pcXVlKGMoKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCgoKIyBbMV0gQXZlcmFnZSBvZiBkaWZmZXJlbnRpYWwgbG9vcCBzY29yZXMgZm9yIGVhY2ggZ2VuZQojIyBSTkEgb25seQpmY0N1dG9mZiA8LSAwLjUKYWxwaGEgPC0gMC4wNQptYXhMb2cyRkMgPC0gMgoKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU09bd2hpY2gubWF4KGFicyhsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPKSldLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQSwgIjJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBjKCksICIxVVAiLCAiME5PIikpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBzaHJsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpCgojZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiZ2VuZV9hdmdTY29yZV9mY19kVEFHX3Atbi50c3YiKSwgc2VwID0gIlx0IikKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2hybG9nMmZjTWF4LCB5ID0gbWVhbl9kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHRfcmVwZWwoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIGdndGl0bGUoImRUQUciKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjBOTyIgPSAiZ3JleSIsICIxVVAiID0gInJlZCIsICIyRE9XTiIgPSAiYmx1ZSIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX2F2Z1Njb3JlX2RUQUdfT0VfcC1uX2Fic0xvZ09FIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKIyBObyBGQyBjdXRvZmYgb3B0aW9uIC0gZG93biBvbmx5CnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPW3doaWNoLm1heChhYnMobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTykpXSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQS5ub0ZDY3V0b2ZmLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmlua2VkX2xvZzJGQywgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FX3Atbl9hYnNMb2dPRV9ub0ZDY3V0b2ZmIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKIyMjIyMgQ2xvc2VzdCBQLU4gbG9vcApgYGB7cn0KIyBnZXR0aW5nIGxpc3Qgb2YgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSBSTkEtc2VxIGFuZCBQUk8tc2VxCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CmRpZmYuUFJPLkcxLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMS5kVEFHX3ZzX0cxLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5QUk8uRzIuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzFHMi5kVEFHX0cyLmRUQUdfdnNfRzIuRE1TT19QUk9zZXEudHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhKQojIEltcG9ydGluZyBsb29wIGdlbmUgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSklPiUgCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKCgojIExvYWRpbmcgT0UgbG9vcCBzY29yZQptaW5WYWx1ZSA8LSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID0gbG9nX29ic2V4cF9kVEFHIC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA9IGxvZ19vYnNleHBfQTQ4NSAtIGxvZ19vYnNleHBfRE1TTykKCmdlbmVBbm5vRGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkKCiMgVGVzdGluZyBkaWZmZXJlbnQgd2F5cyB0byBjYWxjdWxhdGUgcmVwcmVzZW50YXRpdmUgZmVhdHVyZSBvZiBsb29wcyBmb3IgZWFjaCBnZW5lCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKZ2VuZUxpc3QuZG93biA8LSB1bmlxdWUoYygoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCmdlbmVMaXN0LmRvd24uUk5BIDwtIChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QuZG93bi5STkEubm9GQ2N1dG9mZiA8LSAoZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QudXBkb3duLlJOQS5ub0ZDY3V0b2ZmIDwtIChkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYpJGVuc2VtYmxfZ2VuZV9pZAoKZ2VuZUxpc3QudXAgPC0gdW5pcXVlKGMoKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCgoKIyBbMV0gQXZlcmFnZSBvZiBkaWZmZXJlbnRpYWwgbG9vcCBzY29yZXMgZm9yIGVhY2ggZ2VuZQojIyBSTkEgb25seQpmY0N1dG9mZiA8LSAwLjUKYWxwaGEgPC0gMC4wNQptYXhMb2cyRkMgPC0gMgoKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgZ2VuZSwgZGlzdGFuY2UpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSAKICBzbGljZV9taW4oZGlzdGFuY2UsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgYygpLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKI2Z3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR19wLW4udHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FX3Atbl9jbG9zZXN0TG9nT0UiKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgojIE5vIEZDIGN1dG9mZiBvcHRpb24gLSBkb3duIG9ubHkKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgZ2VuZSwgZGlzdGFuY2UpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHNsaWNlX21pbihkaXN0YW5jZSwgd2l0aF90aWVzID0gRkFMU0UpICU+JSAKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQS5ub0ZDY3V0b2ZmLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGMoKSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmlua2VkX2xvZzJGQywgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FX3Atbl9jbG9zZXN0TG9nT0Vfbm9GQ2N1dG9mZiIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyBGYXJ0aGVzdCBQLU4gbG9vcApgYGB7cn0KIyBnZXR0aW5nIGxpc3Qgb2YgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSBSTkEtc2VxIGFuZCBQUk8tc2VxCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CmRpZmYuUFJPLkcxLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMS5kVEFHX3ZzX0cxLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5QUk8uRzIuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzFHMi5kVEFHX0cyLmRUQUdfdnNfRzIuRE1TT19QUk9zZXEudHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhKQojIEltcG9ydGluZyBsb29wIGdlbmUgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSklPiUgCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKCgojIExvYWRpbmcgT0UgbG9vcCBzY29yZQptaW5WYWx1ZSA8LSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID0gbG9nX29ic2V4cF9kVEFHIC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA9IGxvZ19vYnNleHBfQTQ4NSAtIGxvZ19vYnNleHBfRE1TTykKCmdlbmVBbm5vRGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkKCiMgVGVzdGluZyBkaWZmZXJlbnQgd2F5cyB0byBjYWxjdWxhdGUgcmVwcmVzZW50YXRpdmUgZmVhdHVyZSBvZiBsb29wcyBmb3IgZWFjaCBnZW5lCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKZ2VuZUxpc3QuZG93biA8LSB1bmlxdWUoYygoZGlmZi5STkEuRzEuZFRBRyAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAwKSkkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgIChkaWZmLlBSTy5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCmdlbmVMaXN0LmRvd24uUk5BIDwtIChkaWZmLlJOQS5HMS5kVEFHICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QuZG93bi5STkEubm9GQ2N1dG9mZiA8LSAoZGlmZi5STkEuRzEuZFRBRy5ub0ZDY3V0b2ZmICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IDApKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QudXBkb3duLlJOQS5ub0ZDY3V0b2ZmIDwtIChkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYpJGVuc2VtYmxfZ2VuZV9pZAoKZ2VuZUxpc3QudXAgPC0gdW5pcXVlKGMoKGRpZmYuUk5BLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcxLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgKGRpZmYuUFJPLkcyLmRUQUcgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gMCkpJGVuc2VtYmxfZ2VuZV9pZCkpCgoKIyBbMV0gQXZlcmFnZSBvZiBkaWZmZXJlbnRpYWwgbG9vcCBzY29yZXMgZm9yIGVhY2ggZ2VuZQojIyBSTkEgb25seQpmY0N1dG9mZiA8LSAwLjUKYWxwaGEgPC0gMC4wNQptYXhMb2cyRkMgPC0gMgoKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgZ2VuZSwgZGlzdGFuY2UpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSAKICBzbGljZV9tYXgoZGlzdGFuY2UsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgYygpLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKI2Z3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR19wLW4udHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJkVEFHIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImdyZXkiLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19hdmdTY29yZV9kVEFHX09FX3Atbl9mYXJ0aGVzdExvZ09FIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKIyBObyBGQyBjdXRvZmYgb3B0aW9uIC0gZG93biBvbmx5CnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIGdlbmUsIGRpc3RhbmNlKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzbGljZV9tYXgoZGlzdGFuY2UsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEubm9GQ2N1dG9mZiwgIjJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBjKCksICIxVVAiLCAiME5PIikpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBzaHJsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJpbmtlZF9sb2cyRkMsIHkgPSBtZWFuX2RpZmZfc2NvcmUsIGNvbG9yID0gZmxhZywgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGlmZWxzZShmbGFnICE9ICIwTk8iLCBleHRlcm5hbF9nZW5lX25hbWUsIE5BKSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dF9yZXBlbCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiZFRBRyIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJncmV5IiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAyLCAiRkFMU0UiID0gMTkpKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfYXZnU2NvcmVfZFRBR19PRV9wLW5fZmFydGhlc3RMb2dPRV9ub0ZDY3V0b2ZmIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMgQTQ4NSBTY2F0dGVycGxvdAojIyMjIyBQLU4KYGBge3J9CiMgZ2V0dGluZyBsaXN0IG9mIGdlbmVzIG9mIGludGVyZXN0IGZyb20gUk5BLXNlcSBhbmQgUFJPLXNlcQphbHBoYSA8LSAwLjA1CmZjQ3V0b2ZmIDwtIDAuNQpkaWZmLlJOQS5HMS5BNDg1IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5BNDg1LnNlbGVjdGVkMl9HMS4yaS5BNDg1X3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQoKIyBJbXBvcnRpbmcgbG9vcCBnZW5lIGFubm90YXRpb24KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpCgojIFRlc3RpbmcgZGlmZmVyZW50IHdheXMgdG8gY2FsY3VsYXRlIHJlcHJlc2VudGF0aXZlIGZlYXR1cmUgb2YgbG9vcHMgZm9yIGVhY2ggZ2VuZQpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuMmkuQTQ4NV92c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQpnZW5lTGlzdC5kb3duLlJOQSA8LSAoZGlmZi5STkEuRzEuQTQ4NSAlPiUgZHBseXI6OmZpbHRlcihzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYpKSRlbnNlbWJsX2dlbmVfaWQKZ2VuZUxpc3QudXAuUk5BIDwtIChkaWZmLlJOQS5HMS5BNDg1ICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA+IGZjQ3V0b2ZmKSkkZW5zZW1ibF9nZW5lX2lkCgoKIyBbMV0gQXZlcmFnZSBvZiBkaWZmZXJlbnRpYWwgbG9vcCBzY29yZXMgZm9yIGVhY2ggZ2VuZQojIyBSTkEgb25seQpmY0N1dG9mZiA8LSAwLjUKYWxwaGEgPC0gMC4wNQptYXhMb2cyRkMgPC0gNAoKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9BNDg1X0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfQTQ4NV9ETVNPKSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQSwgIjJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC51cC5STkEsICIxVVAiLCAiME5PIikpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBzaHJsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpCgpmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJnZW5lX2F2Z1Njb3JlX2ZjX2RUQUdfcC1uLnRzdiIpLCBzZXAgPSAiXHQiKQoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJsb2cyZmNNYXgsIHkgPSBtZWFuX2RpZmZfc2NvcmUsIGNvbG9yID0gZmxhZywgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGlmZWxzZShmbGFnICE9ICIwTk8iLCBleHRlcm5hbF9nZW5lX25hbWUsIE5BKSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dF9yZXBlbCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiQTQ4NSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJibGFjayIsICIxVVAiID0gInJlZCIsICIyRE9XTiIgPSAiYmx1ZSIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX2F2Z1Njb3JlX0E0ODVfcC1uX2RpZmZDdXRvZmZfIiwgZGlmZkN1dG9mZikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKIyBbMl0gU3VtIG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSA0Cgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKHN1bV9kaWZmX3Njb3JlID0gc3VtKGRpZmZfQTQ4NV9ETVNPKSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQSwgIjJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC51cC5STkEsICIxVVAiLCAiME5PIikpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBzaHJsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpCgpmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJnZW5lX3N1bVNjb3JlX2ZjX2RUQUdfcC1uLnRzdiIpLCBzZXAgPSAiXHQiKQoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJsb2cyZmNNYXgsIHkgPSBzdW1fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJBNDg1IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImJsYWNrIiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAyLCAiRkFMU0UiID0gMTkpKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfc3VtU2NvcmVfQTQ4NV9wLW5fZGlmZkN1dG9mZl8iLCBkaWZmQ3V0b2ZmKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIyBbM10gTWF4IG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSA0Cgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1heF9hYnNfZGlmZl9zY29yZSA9IGRpZmZfQTQ4NV9ETVNPW3doaWNoLm1heChhYnMoZGlmZl9BNDg1X0RNU08pKV0sIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QudXAuUk5BLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiZ2VuZV9tYXhBYnNTY29yZV9mY19kVEFHX3Atbi50c3YiKSwgc2VwID0gIlx0IikKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2hybG9nMmZjTWF4LCB5ID0gbWF4X2Fic19kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHRfcmVwZWwoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIGdndGl0bGUoIkE0ODUiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjBOTyIgPSAiYmxhY2siLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19tYXhBYnNTY29yZV9BNDg1X3Atbl9kaWZmQ3V0b2ZmXyIsIGRpZmZDdXRvZmYpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCmBgYAojIyMjIyBQLVBFCmBgYHtyfQojIGdldHRpbmcgbGlzdCBvZiBnZW5lcyBvZiBpbnRlcmVzdCBmcm9tIFJOQS1zZXEgYW5kIFBSTy1zZXEKYWxwaGEgPC0gMC4wNQpmY0N1dG9mZiA8LSAwLjUKZGlmZi5STkEuRzEuQTQ4NSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuMmkuQTQ4NV92c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKCiMgSW1wb3J0aW5nIGxvb3AgZ2VuZSBhbm5vdGF0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpkaWZmQ3V0b2ZmIDwtIDAuMgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gZGlmZkN1dG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiKSklPiUgCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKCiMgVGVzdGluZyBkaWZmZXJlbnQgd2F5cyB0byBjYWxjdWxhdGUgcmVwcmVzZW50YXRpdmUgZmVhdHVyZSBvZiBsb29wcyBmb3IgZWFjaCBnZW5lCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5BNDg1LnNlbGVjdGVkMl9HMS4yaS5BNDg1X3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmdlbmVMaXN0LmRvd24uUk5BIDwtIChkaWZmLlJOQS5HMS5BNDg1ICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZikpJGVuc2VtYmxfZ2VuZV9pZApnZW5lTGlzdC51cC5STkEgPC0gKGRpZmYuUk5BLkcxLkE0ODUgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gZmNDdXRvZmYpKSRlbnNlbWJsX2dlbmVfaWQKCgojIFsxXSBBdmVyYWdlIG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSA0Cgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9BNDg1X0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LnVwLlJOQSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCmZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR19wLXBlLnRzdiIpLCBzZXAgPSAiXHQiKQoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJsb2cyZmNNYXgsIHkgPSBtZWFuX2RpZmZfc2NvcmUsIGNvbG9yID0gZmxhZywgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGlmZWxzZShmbGFnICE9ICIwTk8iLCBleHRlcm5hbF9nZW5lX25hbWUsIE5BKSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dF9yZXBlbCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiQTQ4NSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJibGFjayIsICIxVVAiID0gInJlZCIsICIyRE9XTiIgPSAiYmx1ZSIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX2F2Z1Njb3JlX0E0ODVfcC1wZV9kaWZmQ3V0b2ZmXyIsIGRpZmZDdXRvZmYpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCiMgWzJdIFN1bSBvZiBkaWZmZXJlbnRpYWwgbG9vcCBzY29yZXMgZm9yIGVhY2ggZ2VuZQojIyBSTkEgb25seQpmY0N1dG9mZiA8LSAwLjUKYWxwaGEgPC0gMC4wNQptYXhMb2cyRkMgPC0gNAoKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9BNDg1X0RNU08sIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShzdW1fZGlmZl9zY29yZSA9IHN1bShkaWZmX0E0ODVfRE1TTyksIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QudXAuUk5BLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiZ2VuZV9zdW1TY29yZV9mY19kVEFHX3AtcGUudHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IHN1bV9kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHRfcmVwZWwoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIGdndGl0bGUoIkE0ODUiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjBOTyIgPSAiYmxhY2siLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19zdW1TY29yZV9BNDg1X3AtcGVfZGlmZkN1dG9mZl8iLCBkaWZmQ3V0b2ZmKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIyBbM10gTWF4IG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSA0Cgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1heF9hYnNfZGlmZl9zY29yZSA9IGRpZmZfQTQ4NV9ETVNPW3doaWNoLm1heChhYnMoZGlmZl9BNDg1X0RNU08pKV0sIC5ncm91cHMgPSAnZHJvcCcpCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QuZG93bi5STkEsICIyRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZUxpc3QudXAuUk5BLCAiMVVQIiwgIjBOTyIpKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgc2hybG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKQoKZndyaXRlKHRlbXAsIGhlcmUoY29uc2Vuc3VzRGlyLCAiZ2VuZV9tYXhBYnNTY29yZV9mY19kVEFHX3AtcGUudHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1heF9hYnNfZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJBNDg1IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImJsYWNrIiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAyLCAiRkFMU0UiID0gMTkpKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfbWF4QWJzU2NvcmVfQTQ4NV9wLXBlX2RpZmZDdXRvZmZfIiwgZGlmZkN1dG9mZikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIFAtUwpgYGB7cn0KIyBnZXR0aW5nIGxpc3Qgb2YgZ2VuZXMgb2YgaW50ZXJlc3QgZnJvbSBSTkEtc2VxIGFuZCBQUk8tc2VxCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CmRpZmYuUk5BLkcxLkE0ODUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLjJpLkE0ODVfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCgojIEltcG9ydGluZyBsb29wIGdlbmUgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVMiKSklPiUgCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkKCiMgVGVzdGluZyBkaWZmZXJlbnQgd2F5cyB0byBjYWxjdWxhdGUgcmVwcmVzZW50YXRpdmUgZmVhdHVyZSBvZiBsb29wcyBmb3IgZWFjaCBnZW5lCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5BNDg1LnNlbGVjdGVkMl9HMS4yaS5BNDg1X3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmdlbmVMaXN0LmRvd24uUk5BIDwtIChkaWZmLlJOQS5HMS5BNDg1ICU+JSBkcGx5cjo6ZmlsdGVyKHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZikpJGVuc2VtYmxfZ2VuZV9pZApnZW5lTGlzdC51cC5STkEgPC0gKGRpZmYuUk5BLkcxLkE0ODUgJT4lIGRwbHlyOjpmaWx0ZXIoc2hyaW5rZWRfbG9nMkZDID4gZmNDdXRvZmYpKSRlbnNlbWJsX2dlbmVfaWQKCgojIFsxXSBBdmVyYWdlIG9mIGRpZmZlcmVudGlhbCBsb29wIHNjb3JlcyBmb3IgZWFjaCBnZW5lCiMjIFJOQSBvbmx5CmZjQ3V0b2ZmIDwtIDAuNQphbHBoYSA8LSAwLjA1Cm1heExvZzJGQyA8LSA0Cgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9BNDg1X0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LnVwLlJOQSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCmZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfYXZnU2NvcmVfZmNfZFRBR19wLXMudHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IG1lYW5fZGlmZl9zY29yZSwgY29sb3IgPSBmbGFnLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGZsYWcgIT0gIjBOTyIsIGV4dGVybmFsX2dlbmVfbmFtZSwgTkEpLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBhcy5mYWN0b3IobWF4RmxhZykpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBnZ3RpdGxlKCJBNDg1IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLSBkaWZmQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1mY0N1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwTk8iID0gImJsYWNrIiwgIjFVUCIgPSAicmVkIiwgIjJET1dOIiA9ICJibHVlIikpICsgICMgQ29ycmVjdGVkIGNvbG9yIG1hcHBpbmcKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAyLCAiRkFMU0UiID0gMTkpKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfdnNfYXZnU2NvcmVfQTQ4NV9wLXNfZGlmZkN1dG9mZl8iLCBkaWZmQ3V0b2ZmKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA3CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgojIFsyXSBTdW0gb2YgZGlmZmVyZW50aWFsIGxvb3Agc2NvcmVzIGZvciBlYWNoIGdlbmUKIyMgUk5BIG9ubHkKZmNDdXRvZmYgPC0gMC41CmFscGhhIDwtIDAuMDUKbWF4TG9nMkZDIDwtIDQKCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfQTQ4NV9ETVNPLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUoc3VtX2RpZmZfc2NvcmUgPSBzdW0oZGlmZl9BNDg1X0RNU08pLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LmRvd24uUk5BLCAiMkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVMaXN0LnVwLlJOQSwgIjFVUCIsICIwTk8iKSksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIHNocmxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykKCmZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgImdlbmVfc3VtU2NvcmVfZmNfZFRBR19wLXMudHN2IiksIHNlcCA9ICJcdCIpCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IHNocmxvZzJmY01heCwgeSA9IHN1bV9kaWZmX3Njb3JlLCBjb2xvciA9IGZsYWcsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBpZmVsc2UoZmxhZyAhPSAiME5PIiwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBOQSksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGFzLmZhY3RvcihtYXhGbGFnKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3RleHRfcmVwZWwoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIGdndGl0bGUoIkE0ODUiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtIGRpZmZDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLWZjQ3V0b2ZmLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjBOTyIgPSAiYmxhY2siLCAiMVVQIiA9ICJyZWQiLCAiMkRPV04iID0gImJsdWUiKSkgKyAgIyBDb3JyZWN0ZWQgY29sb3IgbWFwcGluZwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IDIsICJGQUxTRSIgPSAxOSkpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ192c19zdW1TY29yZV9BNDg1X3Atc19kaWZmQ3V0b2ZmXyIsIGRpZmZDdXRvZmYpCmhlaWdodCA8LSA0CndpZHRoIDwtIDcKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgojIFszXSBNYXggb2YgZGlmZmVyZW50aWFsIGxvb3Agc2NvcmVzIGZvciBlYWNoIGdlbmUKIyMgUk5BIG9ubHkKZmNDdXRvZmYgPC0gMC41CmFscGhhIDwtIDAuMDUKbWF4TG9nMkZDIDwtIDQKCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfQTQ4NV9ETVNPLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWF4X2Fic19kaWZmX3Njb3JlID0gZGlmZl9BNDg1X0RNU09bd2hpY2gubWF4KGFicyhkaWZmX0E0ODVfRE1TTykpXSwgLmdyb3VwcyA9ICdkcm9wJykKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC5kb3duLlJOQSwgIjJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lTGlzdC51cC5STkEsICIxVVAiLCAiME5PIikpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBzaHJsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpCgpmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsICJnZW5lX21heEFic1Njb3JlX2ZjX2RUQUdfcC1zLnRzdiIpLCBzZXAgPSAiXHQiKQoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBzaHJsb2cyZmNNYXgsIHkgPSBtYXhfYWJzX2RpZmZfc2NvcmUsIGNvbG9yID0gZmxhZywgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGlmZWxzZShmbGFnICE9ICIwTk8iLCBleHRlcm5hbF9nZW5lX25hbWUsIE5BKSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKG1heEZsYWcpKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fdGV4dF9yZXBlbCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiQTQ4NSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0gZGlmZkN1dG9mZiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtZmNDdXRvZmYsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiME5PIiA9ICJibGFjayIsICIxVVAiID0gInJlZCIsICIyRE9XTiIgPSAiYmx1ZSIpKSArICAjIENvcnJlY3RlZCBjb2xvciBtYXBwaW5nCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gMiwgIkZBTFNFIiA9IDE5KSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX3ZzX21heEFic1Njb3JlX0E0ODVfcC1zX2RpZmZDdXRvZmZfIiwgZGlmZkN1dG9mZikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyBbMi4xMV0gSG93IG1hbnkgbG9vcHMgcGVyIGdlbmU/CmBgYHtyfQojIElNUE9SVElORyBHRU5FIEFOTk8gREFUQSBGT1IgUC1OIExPT1BTCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEsCiAgICAgICAgICAgICAgICBwZWFrSUQgPSBwYXN0ZShjaHJvbTEsIHN0YXJ0MSwgc3RhcnQyLCBzZXAgPSAiXyIpKQoKCiMgQ291bnRpbmcgbnVtYmVyIG9mIGxvb3AgcGVyIGdlbmVzCnRlbXBTdW0gPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KHBlYWtJRCwgZ2VuZSwgQW5ubzIpICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSAgc3VtbWFyaXplKAogICAgcGVhayA9IGxpc3QocGVha0lEKSwKICAgIGFubm8yID0gbGlzdChBbm5vMiksCiAgICBjb3VudCA9IG4oKSkKCmdncGxvdCh0ZW1wU3VtLCBhZXMoeCA9IGNvdW50KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgZ2d0aXRsZSgiIyBvZiBQLU4gbG9vcHMgZm9yIGVhY2ggZ2VuZSIpICsgc2NhbGVfeV9sb2cxMCgpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCiMjIFsyLjExLjJdIFN1cGVyRW5oYW5jZXI/CmBgYHtyfQojIElNUE9SVElORyBHRU5FIEFOTk8gREFUQSBGT1IgUC1OIExPT1BTCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpCgp0ZW1wU0UgPC0gZ2VuZUFubm9EYXRhICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSBzdW1tYXJpemUoU0UgPSBpZmVsc2UoYW55KEFubm9TRSA9PSAiU0UiKSwgMSwgMCkpCgoKZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAyLnRzdiIpKSRnZW5lCmdyb3VwNSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDUudHN2IikpJGdlbmUKZ3JvdXA4IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwOC50c3YiKSkkZ2VuZQoKCnRlbXBTRSA8LSB0ZW1wU0UgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShnZW5lICVpbiUgZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdyb3VwMiwgImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ3JvdXA1LCAiZ3JvdXA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ3JvdXA4LCAiZ3JvdXA4IiwgTkEpKSkpKSAlPiUgCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKcGVyYy5ncm91cDEgPC0gbnJvdyh0ZW1wU0UgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwMSIsIFNFID09IDEpKS8KICBucm93KHRlbXBTRSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAxIikpCgpwZXJjLmdyb3VwMiA8LSBucm93KHRlbXBTRSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAyIiwgU0UgPT0gMSkpLwogIG5yb3codGVtcFNFICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJncm91cDIiKSkKCnBlcmMuZ3JvdXA1IDwtIG5yb3codGVtcFNFICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJncm91cDUiLCBTRSA9PSAxKSkvCiAgbnJvdyh0ZW1wU0UgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwNSIpKQoKcGVyYy5ncm91cDggPC0gbnJvdyh0ZW1wU0UgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwOCIsIFNFID09IDEpKS8KICBucm93KHRlbXBTRSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXA4IikpCgp0ZW1wUGxvdCA8LSB0aWJibGUoZ3JvdXAgPSBjKCJncm91cDEiLCAiZ3JvdXAyIiwgImdyb3VwNSIsICJncm91cDgiKSwKICAgICAgICAgICAgICAgICAgIHBlcmMgPSBjKHBlcmMuZ3JvdXAxLCBwZXJjLmdyb3VwMiwgcGVyYy5ncm91cDUsIHBlcmMuZ3JvdXA4KSkKCmdncGxvdCh0ZW1wUGxvdCwgYWVzKHggPSBncm91cCwgeSA9IHBlcmMpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2NsYXNzaWMoKSArIHlsaW0oMCwgMC4yKQpgYGAKCgpgYGB7cn0KcGxvdF9pbnNTY29yZSA8LSBmdW5jdGlvbih0ZW1wLnRiLCBub3RlLCB5bWluID0gMCwgeW1heCA9IDEuNSl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICBwMTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQogIHAxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA4IiksIDUpCiAgcDI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDUiKSwgNSkKICBwMjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQogIHA1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDUiLCAiZ3JvdXA4IiksIDUpCiAgCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSBncm91cCwgeSA9IHNjb3JlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoeW1pbiwgeW1heCkpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSB5bWluICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTg6ICIsIGNvbnZQdmFsdWUocDE4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNTogIiwgY29udlB2YWx1ZShwMjUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwNTg6ICIsY29udlB2YWx1ZSggcDU4KSwgIlxuIiksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uX3Njb3JlXyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAzCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCiMgRE1TTwp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGJvdW5kYXJ5SW5zU2NvcmVfRE1TTykKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfRE1TTyIpCgoKCmBgYAoKCiMjIFsyLjEyXSBIb3cgbWFueSBsb29wcy9kaXN0YW5jZSBwZXIgZ2VuZSBpbiBlYWNoIHF1YWRyYW50PwojIyMjIGRUQUcgd2l0aCBiaW5hcnkgZ3JvdXBpbmcKIyMjIyMgU3BsaXR0aW5nIGdlbmVzIHRvIGdyb3VwCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCgojIyBEaXZpZGluZyBnZW5lcyBpbnRvIGdyb3Vwcwp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX2RUQUdfRE1TTywgZGlzdGFuY2UsIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfZFRBR19ETVNPKSwKICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oZGlzdGFuY2UpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQoKbWF4TG9nMkZDID0gMgoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcm9wX25hKHNocmlua2VkX2xvZzJGQykKCgp0ZW1wIDwtIHRlbXAgJT4lCiAgZHBseXI6Om11dGF0ZShncm91cCA9IGlmZWxzZShwYWRqIDwgMC4wNSAmIHNocmlua2VkX2xvZzJGQyA8IDAsIDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1lYW5fZGlmZl9zY29yZSA8IDAsIDIsIDMpKSkKCgoKZmNDdXRvZmYgPC0gMC41CmRpZmZDdXRvZmYgPC0gMC4yCgpnZW5lLmdyb3VwMSA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAxKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAyKSkkZ2VuZQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMSkpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAyKSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSwgc2VwID0gIlx0IikKCgojIEFkZGluZyBncm91cCBpbmZvcm1hdGlvbiB0byBnZW5lQW5ubwpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAyLCAiZ3JvdXAyIiwgTkEpKQopCgoKYGBgCiMjIyMjIC0gR08gZm9yIGVhY2ggZ3JvdXAKCmBgYHtyfQoKZ2VuZS5ncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdlbmUuZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKR08xIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwMSwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkKR08yIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwMiwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkKR08xLmRmIDwtIGFzLmRhdGEuZnJhbWUoR08xKQpHTzIuZGYgPC0gYXMuZGF0YS5mcmFtZShHTzIpCiMgZndyaXRlKEdPMS5kZiwgaGVyZSgiR09fYmluYXJ5X2dyb3VwMS50c3YiKSwgc2VwID0gIlx0IikKIyBmd3JpdGUoR08yLmRmLCBoZXJlKCJHT19iaW5hcnlfZ3JvdXAyLnRzdiIpLCBzZXAgPSAiXHQiKQpHTzEuZGYgPC0gZnJlYWQoaGVyZSgiR09fYmluYXJ5X2dyb3VwMS50c3YiKSkKR08yLmRmIDwtIGZyZWFkKGhlcmUoIkdPX2JpbmFyeV9ncm91cDIudHN2IikpCgpzdWJzZXQxIDwtIEdPMS5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDEiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0MSRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDEkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKCnN1YnNldDIgPC0gR08yLmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiR3JvdXAgMiIpICU+JQogIGRwbHlyOjphcnJhbmdlKHAuYWRqdXN0KQpzdWJzZXQyJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MiRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQoKCkdPbGlzdCA8LSBmYWN0b3IoYygiR086MDAwMTgyNCIsICJHTzowMDMwODc5IiwgIkdPOjAwMjE5NTMiLCAiR086MDAxOTgyNyIsIAogICAgICAgICAgICAgICAgICJHTzowMDIyNjEzIiwgIkdPOjAwNTA3NjciLCAiR086MDAzNDQ3MCIsICJHTzowMDE2MDU1IiwgCiAgICAgICAgICAgICAgICAgIkdPOjAwMDYzOTciLCAiR086MDAzMDkwMCIsICJHTzowMDA4MzgwIikpCgpkYXRhIDwtIGJpbmRfcm93cyhzdWJzZXQxLCBzdWJzZXQyKSAlPiUKICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgR09saXN0KQoKZGVzY09yZGVyIDwtIHNvcnQodW5pcXVlKGRhdGEkRGVzY3JpcHRpb24pKVtjKDQsIDEwLCAyLCAxLCAzLCAxMSwgNywgOCwgNiwgNSwgOSldCnBWYWx1ZUxvZ01heCA8LSAxMApkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUocFZhbHVlTG9nID0gbWluKC1sb2cxMChwLmFkanVzdCksIHBWYWx1ZUxvZ01heCkpCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBmYWN0b3IoRGVzY3JpcHRpb24sIGxldmVscyA9IGRlc2NPcmRlciksIHNpemUgPSBwVmFsdWVMb2csIGZpbGwgPSBHZW5lUmF0aW8pKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgICAgICAgICMgRW5zdXJlcyBhIHBvaW50IHdpdGggYW4gb3V0bGluZQogICAgICAgICAgICAgc3Ryb2tlID0gMSpwdFRvTU0pICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjUsIDIpKSArICAjIFNldCBtaW4gYW5kIG1heCBwb2ludCBzaXplcyBoZXJlCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiNDQjMzM0EiLAogICAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDAsIDEpLAogICAgICAgICAgICAgICAgICAgICAgb29iID0gc2NhbGVzOjpzcXVpc2gsICMgRGVmaW5lIGdyYWRpZW50IGNvbG9ycwogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICMgQWRqdXN0IGhlaWdodCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICApCiAgKSArIAogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgdGhlbWVfYncoKSArICAjIEFwcGx5IHRoZW1lX2J3IGZpcnN0LCBzbyBjdXN0b20gdGhlbWUgc2V0dGluZ3MgY29tZSBhZnRlcgogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksICAjIE92ZXJyaWRlIHRoZW1lX2J3IHBhbmVsCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgICAgICAgICAjIEVuc3VyZSBzaXplIGlzIHNldCBmb3IgeC1heGlzIHRleHQKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCAgICAgICAgICMgRW5zdXJlIHNpemUgaXMgc2V0IGZvciB5LWF4aXMgdGV4dAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIGxpbmVoZWlnaHQgPSAwLjkgICAgICAgICAgIyBBbGxvd3Mgd3JhcHBpbmcgZm9yIHktYXhpcyBsYWJlbHMgdG8gZml0IGludG8gMiBsaW5lcwogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKQogIAoKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX2JpbmFyeUdyb3VwaW5nIikKd2lkdGggPC0gcGFuZWxTaXplKDIuNSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCnN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyMjIyAtIEF2ZXJhZ2UgbG9vcCBzaXplCmBgYHtyfQojIENoZWNraW5nIGF2ZXJhZ2UgZGlzdGFuY2Ugb2YgbG9vcHMgcGVyIGdlbmUKIyB0ZW1wIGlzIGEgdGliYmxlIHdoZXJlIGRlbHRhIGxvb3AgYW5kIGxvZzJmYyBhcmUgbWVyZ2VkCnRlbXAkZ3JvdXAgPC0gZmFjdG9yKHRlbXAkZ3JvdXApCgp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgJWluJSBjKDEsIDIpKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRtZWFuX2Rpc3RhbmNlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJG1lYW5fZGlzdGFuY2UKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgMSwgMiksIDUpCgoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBtZWFuX2Rpc3RhbmNlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAxMDAwMDAwLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiksCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIApmaWxlTmFtZSA8LSBwYXN0ZTAoInNpemVfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPX2JpbmFyeUdyb3VwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMgpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtTgpgYGB7cn0KIyBDb3VudGluZyBudW1iZXIgb2YgbG9vcCBwZXIgZ2VuZXMKdGVtcFN1bSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QocGVha0lELCBnZW5lLCBBbm5vMikgJT4lIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lICBzdW1tYXJpemUoCiAgICBwZWFrID0gbGlzdChwZWFrSUQpLAogICAgYW5ubzIgPSBsaXN0KEFubm8yKSwKICAgIGNvdW50ID0gbigpKQoKdGVtcFN1bSA8LSB0ZW1wU3VtICU+JSBkcGx5cjo6bXV0YXRlKAogIGdyb3VwID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMiwgImdyb3VwMiIsIE5BKSkKKSAlPiUgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKSAlPiUgZHBseXI6OmZpbHRlcihncm91cCAlaW4lIGMoImdyb3VwMSIsICJncm91cDIiKSkKCiMgCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRjb3VudAogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRjb3VudAogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFN1bSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wU3VtLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFN1bSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wU3VtLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwNSIsICJncm91cDgiKSwgNSkKCgpwIDwtIGdncGxvdCh0ZW1wU3VtLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjYsCiAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyKSkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gIiMgb2YgUC1OIGxvb3BzIHBlciBnZW5lIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA4KSkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDMsIGxhYmVsID0gcGFzdGUwKCJwdjEyOiAiLCBjb252UHZhbHVlKHB2MTIpKSwKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEpICsKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImNvdW50X2JhcnBsb3RfZGlmZkdyb3VwX2RUQUdfdnNfRE1TT19iaW5hcnlHcm91cCIpCndpZHRoIDwtIHBhbmVsU2l6ZSgwLjgpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gQ291bnRpbmcgbG9vcCB0eXBlcwpgYGB7cn0KIyMjIyMjIwp0ZW1wMiA8LSB0ZW1wU3VtICU+JSByb3d3aXNlKCkgJT4lIG11dGF0ZSh0b3RhbCA9IGxlbmd0aChhbm5vMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wcCA9IHN1bShhbm5vMiA9PSAiUC1QIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wZSA9IHN1bShhbm5vMiA9PSAiUC1FIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wcyA9IHN1bShhbm5vMiA9PSAiUC1TIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9weCA9IHN1bShhbm5vMiA9PSAiUC1YIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGlvX3JlZyA9IChudW1fcHAgKyBudW1fcGUpL3RvdGFsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYXRpb19zdHIgPSBudW1fcHMvdG90YWwpCgojc2F2ZVJEUyh0ZW1wMiwgaGVyZShyZXN1bHREaXIsICJnZW5lX2xvb3BfbGlua19BNDg1LnJkcyIpKQoKCmxvb3BUeXBlIDwtIHRlbXAyICU+JSBncm91cF9ieShncm91cCkgJT4lIHN1bW1hcmlzZShudW1fcHAgPSBzdW0obnVtX3BwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wZSA9IHN1bShudW1fcGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BzID0gc3VtKG51bV9wcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fcHggPSBzdW0obnVtX3B4KSkKCgpsb29wVHlwZUxvbmcgPC0gbG9vcFR5cGUgJT4lIHBpdm90X2xvbmdlcigtZ3JvdXAsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKQoKbG9vcFR5cGVMb25nJHR5cGUgPC0gZmFjdG9yKGxvb3BUeXBlTG9uZyR0eXBlLCBsZXZlbHMgPSBjKCJudW1fcHAiLCAibnVtX3BlIiwgIm51bV9wcyIsICJudW1fcHgiKSkKCiMgUGxvdHRpbmcKZ2dwbG90KGxvb3BUeXBlTG9uZywgYWVzKGZpbGw9dHlwZSwgeT1jb3VudCwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKCmBgYAoKIyMjIyMgLSBMb29wIG51bWJlciBwZXIgZ2VuZTogUC1QCmBgYHtyfQojIyMjIyMjIwojUC1QCmRhdGEgPC0gdGVtcDIgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIG51bV9wcCkKY29sbmFtZXMoZGF0YSkgPC0gYygiZ3JvdXAiLCAiY291bnQiKQpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjYsCiAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyKSkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gIiMgb2YgUC1QIGxvb3BzIHBlciBnZW5lIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA0KSkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDMsIGxhYmVsID0gcGFzdGUwKCJwdjEyOiAiLCBjb252UHZhbHVlKHB2MTIpKSwKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEpICsKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPX3BwX2JpbmFyeUdyb3VwIikKd2lkdGggPC0gcGFuZWxTaXplKDAuOCkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgLSBMb29wIG51bWJlciBwZXIgZ2VuZTogUC1FCmBgYHtyfQojIyMjIyMjIwojUC1FCmRhdGEgPC0gdGVtcDIgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIG51bV9wZSkKY29sbmFtZXMoZGF0YSkgPC0gYygiZ3JvdXAiLCAiY291bnQiKQpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQoKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjUsIG91dGxpZXIuc2hhcGUgPSBOQSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNiwKICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyB0aGVtZV9jbGFzc2ljKCkgKyAgICAgICAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDIpKSArIAogIGxhYnMoeCA9IE5VTEwsIHkgPSAiIyBvZiBQLUUgbG9vcHMgcGVyIGdlbmUiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDQpKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAwLjUsCiAgICBmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siCiAgKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMywgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIGNvbnZQdmFsdWUocHYxMikpLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSkgKwogIHRoZW1lKAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKQoKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImNvdW50X2JhcnBsb3RfZGlmZkdyb3VwX2RUQUdfdnNfRE1TT19wZV9iaW5hcnlHcm91cCIpCndpZHRoIDwtIHBhbmVsU2l6ZSgwLjgpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtUwpgYGB7cn0KIyMjIyMjIyMKI1AtUwpkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcHMpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKcHYxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDIiKSwgNSkKCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjYsCiAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyKSkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gIiMgb2YgUC1TIGxvb3BzIHBlciBnZW5lIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA0KSkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDMsIGxhYmVsID0gcGFzdGUwKCJwdjEyOiAiLCBjb252UHZhbHVlKHB2MTIpKSwKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEpICsKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkKCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJjb3VudF9iYXJwbG90X2RpZmZHcm91cF9kVEFHX3ZzX0RNU09fcHNfYmluYXJ5R3JvdXAiKQp3aWR0aCA8LSBwYW5lbFNpemUoMC44KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuNSkqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIGRUQUcKIyMjIyMgLSBTcGxpdHRpbmcgZ2VuZXMgdG8gZ3JvdXBzCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCgoKIyMgRGl2aWRpbmcgZ2VuZXMgaW50byBncm91cHMKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9kVEFHX0RNU08sIGRpc3RhbmNlLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX2RUQUdfRE1TTyksCiAgICAgICAgICAgIG1lYW5fZGlzdGFuY2UgPSBtZWFuKGRpc3RhbmNlKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykKCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCm1heExvZzJGQyA9IDIKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHJvcF9uYShzaHJpbmtlZF9sb2cyRkMpCgoKZmNDdXRvZmYgPC0gMC41CmRpZmZDdXRvZmYgPC0gMC4yCiMgCnRlbXAgPC0gdGVtcCAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gaWZlbHNlKG1lYW5fZGlmZl9zY29yZSA8IC1kaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZiwgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc2hyaW5rZWRfbG9nMkZDIDxmY0N1dG9mZiwgMiwgMykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1lYW5fZGlmZl9zY29yZSA8IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZiwgNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8IGZjQ3V0b2ZmLCA1LCA2KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZiwgNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8IGZjQ3V0b2ZmLCA4LCA5KSkpKSkKCgpnZW5lLmdyb3VwMSA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAxKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAyKSkkZ2VuZQpnZW5lLmdyb3VwMyA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAzKSkkZ2VuZQpnZW5lLmdyb3VwNCA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA0KSkkZ2VuZQpnZW5lLmdyb3VwNSA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA1KSkkZ2VuZQpnZW5lLmdyb3VwNiA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA2KSkkZ2VuZQpnZW5lLmdyb3VwNyA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA3KSkkZ2VuZQpnZW5lLmdyb3VwOCA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA4KSkkZ2VuZQpnZW5lLmdyb3VwOSA8LSAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA5KSkkZ2VuZQoKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDEpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAxLnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMikpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDIudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAzKSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMy50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDQpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA0LnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNSkpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDUudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA2KSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwNi50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDcpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA3LnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gOCkpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA5KSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwOS50c3YiKSwgc2VwID0gIlx0IikKCgojIEFkZGluZyBncm91cCBpbmZvcm1hdGlvbiB0byBnZW5lQW5ubwpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAyLCAiZ3JvdXAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMywgImdyb3VwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA0LCAiZ3JvdXA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA1LCAiZ3JvdXA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNiwgImdyb3VwNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA3LCAiZ3JvdXA3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA4LCAiZ3JvdXA4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwOSwgImdyb3VwOSIsIE5BKSkpKSkpKSkpCikKCgpgYGAKIyMjIyMgLSBHTyBmb3IgZWFjaCBncm91cAoKYGBge3J9CkdPMSA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZS5ncm91cDEsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTzIgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmUuZ3JvdXAyLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKR081IDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwNSwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCkdPOCA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZS5ncm91cDgsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQoKR08xLmRmIDwtIGFzLmRhdGEuZnJhbWUoR08xKQpHTzIuZGYgPC0gYXMuZGF0YS5mcmFtZShHTzIpCkdPMy5kZiA8LSBhcy5kYXRhLmZyYW1lKEdPNSkKR080LmRmIDwtIGFzLmRhdGEuZnJhbWUoR084KQoKc3Vic2V0MSA8LSBHTzEuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJncm91cDEiKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgZ3IgPSBzYXBwbHkoR2VuZVJhdGlvLCBmdW5jdGlvbih4KSB7CiAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiAgICAgICMgQ29udmVydCB0byBudW1lcmljIGFuZCBwZXJmb3JtIHRoZSBkaXZpc2lvbgogICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiAgICB9KQogICkgJT4lIGRwbHlyOjphcnJhbmdlKGRlc2MoZ3IpKQpzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiZ3JvdXAyIikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKc3Vic2V0MyA8LSBHTzMuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gImdyb3VwMyIpICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKICAgICAgIyBTcGxpdCB0aGUgc3RyaW5nIGJ5ICIvIgogICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiAgICAgIGFzLm51bWVyaWMocGFydHNbMV0pIC8gYXMubnVtZXJpYyhwYXJ0c1syXSkKICAgIH0pCiAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCgpHT2xpc3QgPC0gZmFjdG9yKGMoIkdPOjAwMzMwMDIiLCAiR086MDA3MDM3MyIsICJHTzowMDQ4NzMwIiwgIkdPOjAwMzExMDMiLAogICAgICAgICAgICAgICAgICJHTzowMDIyNjEzIiwgIkdPOjAwNTA3NjciLCAiR086MDAzNDQ3MCIsICJHTzowMDE2MDU1IiwgCiAgICAgICAgICAgICAgICAgIkdPOjAwMDYzOTciLCAiR086MDAzMDkwMCIsICJHTzowMDA4MzgwIikpCgpkYXRhIDwtIGJpbmRfcm93cyhiaW5kX3Jvd3Moc3Vic2V0MSwgc3Vic2V0MiksIHN1YnNldDMpICU+JQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCgpkZXNjT3JkZXIgPC0gc29ydCh1bmlxdWUoZGF0YSREZXNjcmlwdGlvbikpW2MoMSwgMiwgNSwgNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMywgNCwgNiwgOCwgOSwgMTAsIDExKV0KCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBmYWN0b3IoRGVzY3JpcHRpb24sIGxldmVsID0gZGVzY09yZGVyKSwgY29sb3IgPSBwLmFkanVzdCwgc2l6ZSA9IGdyKSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbGltaXRzID0gYygwLCAwLjA1KSkgKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgMykpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICAjIFNldCBheGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBheGlzIHRpdGxlIHNpemUgKGlmIG5vdCByZW1vdmVkKQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgbGVnZW5kIHRleHQgc2l6ZQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIAoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsICIuLiIsICJHTyIsICJHT19ncm91cHMiKQpoZWlnaHQgPSAyCndpZHRoID0gMy41CnN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgoKIyMjIyMgLSBBdmVyYWdlIGxvb3Agc2l6ZQpgYGB7cn0KIyBDaGVja2luZyBhdmVyYWdlIGRpc3RhbmNlIG9mIGxvb3BzIHBlciBnZW5lCiMgdGVtcCBpcyBhIHRpYmJsZSB3aGVyZSBkZWx0YSBsb29wIGFuZCBsb2cyZmMgYXJlIG1lcmdlZAp0ZW1wJGdyb3VwIDwtIGZhY3Rvcih0ZW1wJGdyb3VwKQoKIwp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgJWluJSBjKDEsIDIsIDUsIDgpKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRtZWFuX2Rpc3RhbmNlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJG1lYW5fZGlzdGFuY2UKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgMSwgMiksIDUpCnB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAxLCA1KSwgNSkKcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsIDEsIDgpLCA1KQpwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgMiwgNSksIDUpCnB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAyLCA4KSwgNSkKcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsIDUsIDgpLCA1KQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBtZWFuX2Rpc3RhbmNlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMTAwMDAwMCwgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjE1OiAiLCBwdjE1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBwdjI4LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKICAKICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJzaXplX2JhcnBsb3RfZGlmZkdyb3VwX2RUQUdfdnNfRE1TTyIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyAtIExvb3AgbnVtYmVyIHBlciBnZW5lOiBQLU4KYGBge3J9CiMgQ291bnRpbmcgbnVtYmVyIG9mIGxvb3AgcGVyIGdlbmVzCnRlbXBTdW0gPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KHBlYWtJRCwgZ2VuZSwgQW5ubzIpICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSAgc3VtbWFyaXplKAogICAgcGVhayA9IGxpc3QocGVha0lEKSwKICAgIGFubm8yID0gbGlzdChBbm5vMiksCiAgICBjb3VudCA9IG4oKSkKCnRlbXBTdW0gPC0gdGVtcFN1bSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDEsICJncm91cDEiLAogICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDIsICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAzLCAiZ3JvdXAzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDQsICJncm91cDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDUsICJncm91cDUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA2LCAiZ3JvdXA2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDcsICJncm91cDciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDgsICJncm91cDgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA5LCAiZ3JvdXA5IiwgTkEpKSkpKSkpKSkKKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGdyb3VwICVpbiUgYygiZ3JvdXAxIiwgImdyb3VwMiIsICJncm91cDUiLCAiZ3JvdXA4IikpCgoKIyBURU1QIFNUQVJUCiNnZW5lTGlzdC5ncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAxLnRzdiIpKQojZ2VuZUxpc3QuZ3JvdXAxLnRlbXAgPC0gZ2VuZUxpc3QuZ3JvdXAxICU+JSBkcGx5cjo6bGVmdF9qb2luKHRlbXBTdW0sIGJ5ID0gYygiZ2VuZSIpKQojIFRFTVAgRU5ECgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkY291bnQKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkY291bnQKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKcHYxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDIiKSwgNSkKcHYxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDUiKSwgNSkKcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDgiKSwgNSkKcHYyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMiIsICJncm91cDUiKSwgNSkKcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMiIsICJncm91cDgiKSwgNSkKcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwNSIsICJncm91cDgiKSwgNSkKCgpwIDwtIGdncGxvdCh0ZW1wU3VtLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyKSwgbGltaXRzID0gYygwLCAxMCkpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMywgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjE1OiAiLCBwdjE1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBwdjI4LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSkgKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gQ291bnRpbmcgbG9vcCB0eXBlcwpgYGB7cn0KIyMjIyMjIwp0ZW1wMiA8LSB0ZW1wU3VtICU+JSByb3d3aXNlKCkgJT4lIG11dGF0ZSh0b3RhbCA9IGxlbmd0aChhbm5vMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wcCA9IHN1bShhbm5vMiA9PSAiUC1QIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wZSA9IHN1bShhbm5vMiA9PSAiUC1FIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wcyA9IHN1bShhbm5vMiA9PSAiUC1TIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9weCA9IHN1bShhbm5vMiA9PSAiUC1YIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGlvX3JlZyA9IChudW1fcHAgKyBudW1fcGUpL3RvdGFsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYXRpb19zdHIgPSBudW1fcHMvdG90YWwpCgpzYXZlUkRTKHRlbXAyLCBoZXJlKHJlc3VsdERpciwgImdlbmVfbG9vcF9saW5rLnJkcyIpKQoKCmxvb3BUeXBlIDwtIHRlbXAyICU+JSBncm91cF9ieShncm91cCkgJT4lIHN1bW1hcmlzZShudW1fcHAgPSBzdW0obnVtX3BwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wZSA9IHN1bShudW1fcGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BzID0gc3VtKG51bV9wcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fcHggPSBzdW0obnVtX3B4KSkKCgpsb29wVHlwZUxvbmcgPC0gbG9vcFR5cGUgJT4lIHBpdm90X2xvbmdlcigtZ3JvdXAsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKQoKbG9vcFR5cGVMb25nJHR5cGUgPC0gZmFjdG9yKGxvb3BUeXBlTG9uZyR0eXBlLCBsZXZlbHMgPSBjKCJudW1fcHAiLCAibnVtX3BlIiwgIm51bV9wcyIsICJudW1fcHgiKSkKCiMgUGxvdHRpbmcKZ2dwbG90KGxvb3BUeXBlTG9uZywgYWVzKGZpbGw9dHlwZSwgeT1jb3VudCwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKCmBgYAoKIyMjIyMgLSBMb29wIG51bWJlciBwZXIgZ2VuZTogUC1QCmBgYHtyfQojIyMjIyMjIwojUC1QCmRhdGEgPC0gdGVtcDIgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIG51bV9wcCkKY29sbmFtZXMoZGF0YSkgPC0gYygiZ3JvdXAiLCAiY291bnQiKQpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQpwdjE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQpwdjE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwOCIpLCA1KQpwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQpwdjI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQpwdjU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXA1IiwgImdyb3VwOCIpLCA1KQoKcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IGNvdW50LCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA1LCBieSA9IDIpLCBsaW1pdHMgPSBjKDAsIDUpKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDMsIGxhYmVsID0gcGFzdGUwKCJwdjEyOiAiLCBwdjEyLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTg6ICIsIHB2MTgsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI1OiAiLCBwdjI1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NTg6ICIsIHB2NTgsICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEpKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPX3BwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtRQpgYGB7cn0KIyMjIyMjIyMKI1AtRQpkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcGUpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKcHYxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDIiKSwgNSkKcHYxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDUiKSwgNSkKcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKcHYyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMiIsICJncm91cDUiKSwgNSkKcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMiIsICJncm91cDgiKSwgNSkKcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgYnkgPSAyKSwgbGltaXRzID0gYygwLCA1KSkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAzLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTU6ICIsIHB2MTUsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjE4OiAiLCBwdjE4LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNTogIiwgcHYyNSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2Mjg6ICIsIHB2MjgsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjU4OiAiLCBwdjU4LCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxKSsgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImNvdW50X2JhcnBsb3RfZGlmZkdyb3VwX2RUQUdfdnNfRE1TT19wZSIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyAtIExvb3AgbnVtYmVyIHBlciBnZW5lOiBQLVMKYGBge3J9CiMjIyMjIyMjCiNQLVMKZGF0YSA8LSB0ZW1wMiAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgbnVtX3BzKQpjb2xuYW1lcyhkYXRhKSA8LSBjKCJncm91cCIsICJjb3VudCIpCnB2MTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXAyIiksIDUpCnB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCnB2MTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA4IiksIDUpCnB2MjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA1IiksIDUpCnB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCnB2NTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDUiLCAiZ3JvdXA4IiksIDUpCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjUsIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKyAgICAgICAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDUsIGJ5ID0gMiksIGxpbWl0cyA9IGMoMCwgNSkpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMywgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjE1OiAiLCBwdjE1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBwdjI4LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSkrICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJjb3VudF9iYXJwbG90X2RpZmZHcm91cF9kVEFHX3ZzX0RNU09fcHMiKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgLSBMb29wIG51bWJlciBwZXIgZ2VuZTogUC1YCmBgYHtyfQojIyMjIyMjIwojUC1YCmRhdGEgPC0gdGVtcDIgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIG51bV9weCkKY29sbmFtZXMoZGF0YSkgPC0gYygiZ3JvdXAiLCAiY291bnQiKQpwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQpwdjE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQpwdjE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwOCIpLCA1KQpwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQpwdjI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQpwdjU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXA1IiwgImdyb3VwOCIpLCA1KQoKcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IGNvdW50LCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgICAgICAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA1LCBieSA9IDIpLCBsaW1pdHMgPSBjKDAsIDUpKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDMsIGxhYmVsID0gcGFzdGUwKCJwdjEyOiAiLCBwdjEyLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTg6ICIsIHB2MTgsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI1OiAiLCBwdjI1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NTg6ICIsIHB2NTgsICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDEpKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPX3B4IikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMgQTQ4NQojIyMjIyAtIFNwbGl0dGluZyBnZW5lcyB0byBncm91cHMKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEsCiAgICAgICAgICAgICAgICBwZWFrSUQgPSBwYXN0ZShjaHJvbTEsIHN0YXJ0MSwgc3RhcnQyLCBzZXAgPSAiXyIpKQoKCgojIyBEaXZpZGluZyBnZW5lcyBpbnRvIGdyb3Vwcwp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZGlzdGFuY2UsIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfQTQ4NV9ETVNPKSwKICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oZGlzdGFuY2UpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLjJpLkE0ODVfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRyb3BfbmEoc2hyaW5rZWRfbG9nMkZDKQoKCmZjQ3V0b2ZmIDwtIDAuNQpkaWZmQ3V0b2ZmIDwtIDAuMgojIAp0ZW1wIDwtIHRlbXAgJT4lCiAgZHBseXI6Om11dGF0ZShncm91cCA9IGlmZWxzZShtZWFuX2RpZmZfc2NvcmUgPCAtZGlmZkN1dG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYsIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNocmlua2VkX2xvZzJGQyA8ZmNDdXRvZmYsIDIsIDMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtZWFuX2RpZmZfc2NvcmUgPCBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYsIDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaHJpbmtlZF9sb2cyRkMgPCBmY0N1dG9mZiwgNSwgNikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYsIDcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzaHJpbmtlZF9sb2cyRkMgPCBmY0N1dG9mZiwgOCwgOSkpKSkpCgoKZ2VuZS5ncm91cDEgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMSkpJGdlbmUKZ2VuZS5ncm91cDIgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMikpJGdlbmUKZ2VuZS5ncm91cDMgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMykpJGdlbmUKZ2VuZS5ncm91cDQgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNCkpJGdlbmUKZ2VuZS5ncm91cDUgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNSkpJGdlbmUKZ2VuZS5ncm91cDYgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNikpJGdlbmUKZ2VuZS5ncm91cDcgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNykpJGdlbmUKZ2VuZS5ncm91cDggPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gOCkpJGdlbmUKZ2VuZS5ncm91cDkgPC0gKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gOSkpJGdlbmUKCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAxKSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwMS50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDIpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAyLnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gMykpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDMudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA0KSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwNC50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDUpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gNikpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDYudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZSgodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSA3KSksIGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwNy50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IDgpKSwgaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA4LnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gOSkpLCBoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDkudHN2IiksIHNlcCA9ICJcdCIpCgoKIyBBZGRpbmcgZ3JvdXAgaW5mb3JtYXRpb24gdG8gZ2VuZUFubm8KZ2VuZUFubm9EYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgdW5uZXN0KGdlbmUpICU+JSBkcGx5cjo6bXV0YXRlKAogIGdyb3VwID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMiwgImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDMsICJncm91cDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNCwgImdyb3VwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNSwgImdyb3VwNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDYsICJncm91cDYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNywgImdyb3VwNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwOCwgImdyb3VwOCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDksICJncm91cDkiLCBOQSkpKSkpKSkpKQopCgoKYGBgCiMjIyMjIC0gR08gZm9yIGVhY2ggZ3JvdXAKCmBgYHtyfQpHTzEgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmUuZ3JvdXAxLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKR08yIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwMiwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCkdPMyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZS5ncm91cDMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTzQgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmUuZ3JvdXA0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKR081IDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwNSwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCkdPNiA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZS5ncm91cDYsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTzcgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmUuZ3JvdXA3LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKR084IDwtIGVucmljaEdPKGdlbmUgPSBnZW5lLmdyb3VwOCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCkdPOSA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZS5ncm91cDksIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQoKZG90cGxvdChHTzEsIHNob3dDYXRlZ29yeSA9IDEwKQoKIyAKIyBHTzEuZGYgPC0gYXMuZGF0YS5mcmFtZShHTzEpCiMgR08yLmRmIDwtIGFzLmRhdGEuZnJhbWUoR08yKQojIEdPMy5kZiA8LSBhcy5kYXRhLmZyYW1lKEdPNSkKIyBHTzQuZGYgPC0gYXMuZGF0YS5mcmFtZShHTzgpCiMgCiMgc3Vic2V0MSA8LSBHTzEuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJncm91cDEiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiZ3JvdXAyIikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgc3Vic2V0MyA8LSBHTzMuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gImdyb3VwMyIpICU+JQojICAgZHBseXI6Om11dGF0ZSgKIyAgICAgZ3IgPSBzYXBwbHkoR2VuZVJhdGlvLCBmdW5jdGlvbih4KSB7CiMgICAgICAgIyBTcGxpdCB0aGUgc3RyaW5nIGJ5ICIvIgojICAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQojICAgICAgICMgQ29udmVydCB0byBudW1lcmljIGFuZCBwZXJmb3JtIHRoZSBkaXZpc2lvbgojICAgICAgIGFzLm51bWVyaWMocGFydHNbMV0pIC8gYXMubnVtZXJpYyhwYXJ0c1syXSkKIyAgICAgfSkKIyAgICkgJT4lIGRwbHlyOjphcnJhbmdlKGRlc2MoZ3IpKQojIAojIEdPbGlzdCA8LSBmYWN0b3IoYygiR086MDAzMzAwMiIsICJHTzowMDcwMzczIiwgIkdPOjAwNDg3MzAiLCAiR086MDAzMTEwMyIsCiMgICAgICAgICAgICAgICAgICAiR086MDAyMjYxMyIsICJHTzowMDUwNzY3IiwgIkdPOjAwMzQ0NzAiLCAiR086MDAxNjA1NSIsIAojICAgICAgICAgICAgICAgICAgIkdPOjAwMDYzOTciLCAiR086MDAzMDkwMCIsICJHTzowMDA4MzgwIikpCiMgCiMgZGF0YSA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKHN1YnNldDEsIHN1YnNldDIpLCBzdWJzZXQzKSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCiMgCiMgZGVzY09yZGVyIDwtIHNvcnQodW5pcXVlKGRhdGEkRGVzY3JpcHRpb24pKVtjKDEsIDIsIDUsIDcsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMywgNCwgNiwgOCwgOSwgMTAsIDExKV0KIyAKIyBwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gZmFjdG9yKERlc2NyaXB0aW9uLCBsZXZlbCA9IGRlc2NPcmRlciksIGNvbG9yID0gcC5hZGp1c3QsIHNpemUgPSBncikpICsgCiMgICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsKIyAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJyZWQiLCBoaWdoID0gImJsdWUiLCBsaW1pdHMgPSBjKDAsIDAuMDUpKSArCiMgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDMpKSArCiMgICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwojICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgICMgU2V0IGF4aXMgdGV4dCBzaXplCiMgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgYXhpcyB0aXRsZSBzaXplIChpZiBub3QgcmVtb3ZlZCkKIyAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgbGVnZW5kIHRleHQgc2l6ZQojICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkgCiMgCiMgZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsICIuLiIsICJHTyIsICJHT19ncm91cHMiKQojIGhlaWdodCA9IDIKIyB3aWR0aCA9IDMuNQojIHN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKYGBgCgoKCiMjIyMjIC0gQXZlcmFnZSBsb29wIHNpemUKYGBge3J9CiMgQ2hlY2tpbmcgYXZlcmFnZSBkaXN0YW5jZSBvZiBsb29wcyBwZXIgZ2VuZQojIHRlbXAgaXMgYSB0aWJibGUgd2hlcmUgZGVsdGEgbG9vcCBhbmQgbG9nMmZjIGFyZSBtZXJnZWQKdGVtcCRncm91cCA8LSBmYWN0b3IodGVtcCRncm91cCkKCgojIAojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJG1lYW5fZGlzdGFuY2UKIyAgIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRtZWFuX2Rpc3RhbmNlCiMgICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiMgICByZXR1cm4od2lsJHAudmFsdWUpCiMgfQojIAojIHB2MTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAxLCAyKSwgNSkKIyBwdjE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgMSwgNSksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsIDEsIDgpLCA1KQojIHB2MjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAyLCA1KSwgNSkKIyBwdjI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgMiwgOCksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsIDUsIDgpLCA1KQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBtZWFuX2Rpc3RhbmNlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpCiAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMTAwMDAwMCwgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTU6ICIsIHB2MTUsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTg6ICIsIHB2MTgsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2Mjg6ICIsIHB2MjgsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NTg6ICIsIHB2NTgsICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKICAjIAogIApmaWxlTmFtZSA8LSBwYXN0ZTAoInNpemVfYmFycGxvdF9kaWZmR3JvdXBfQTQ4NV92c19ETVNPIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gNApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtTgpgYGB7cn0KIyBDb3VudGluZyBudW1iZXIgb2YgbG9vcCBwZXIgZ2VuZXMKdGVtcFN1bSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QocGVha0lELCBnZW5lLCBBbm5vMikgJT4lIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lICBzdW1tYXJpemUoCiAgICBwZWFrID0gbGlzdChwZWFrSUQpLAogICAgYW5ubzIgPSBsaXN0KEFubm8yKSwKICAgIGNvdW50ID0gbigpKQoKdGVtcFN1bSA8LSB0ZW1wU3VtICU+JSBkcGx5cjo6bXV0YXRlKAogIGdyb3VwID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMiwgImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDMsICJncm91cDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNCwgImdyb3VwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNSwgImdyb3VwNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDYsICJncm91cDYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNywgImdyb3VwNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwOCwgImdyb3VwOCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDksICJncm91cDkiLCBOQSkpKSkpKSkpKQopICU+JSBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgojIAojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGNvdW50CiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkY291bnQKIyAgIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKIyAgIHJldHVybih3aWwkcC52YWx1ZSkKIyB9CiMgCiMgCiMgcHYxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDIiKSwgNSkKIyBwdjE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFN1bSwiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQojIHB2MTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wU3VtLCJncm91cDEiLCAiZ3JvdXA4IiksIDUpCiMgcHYyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMiIsICJncm91cDUiKSwgNSkKIyBwdjI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFN1bSwiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQojIHB2NTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wU3VtLCJncm91cDUiLCAiZ3JvdXA4IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcFN1bSwgYWVzKHggPSBncm91cCwgeSA9IGNvdW50LCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTAsIGJ5ID0gMikpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDEwKSkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMywgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTU6ICIsIHB2MTUsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MTg6ICIsIHB2MTgsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2Mjg6ICIsIHB2MjgsICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NTg6ICIsIHB2NTgsICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSkgKyAgCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJjb3VudF9iYXJwbG90X2RpZmZHcm91cF9BNDg1X3ZzX0RNU08iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSA0CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgLSBDb3VudGluZyBsb29wIHR5cGVzCmBgYHtyfQojIyMjIyMjCnRlbXAyIDwtIHRlbXBTdW0gJT4lIHJvd3dpc2UoKSAlPiUgbXV0YXRlKHRvdGFsID0gbGVuZ3RoKGFubm8yKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BwID0gc3VtKGFubm8yID09ICJQLVAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BlID0gc3VtKGFubm8yID09ICJQLUUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BzID0gc3VtKGFubm8yID09ICJQLVMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3B4ID0gc3VtKGFubm8yID09ICJQLVgiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0aW9fcmVnID0gKG51bV9wcCArIG51bV9wZSkvdG90YWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGlvX3N0ciA9IG51bV9wcy90b3RhbCkKCnNhdmVSRFModGVtcDIsIGhlcmUocmVzdWx0RGlyLCAiZ2VuZV9sb29wX2xpbmtfQTQ4NS5yZHMiKSkKCgpsb29wVHlwZSA8LSB0ZW1wMiAlPiUgZ3JvdXBfYnkoZ3JvdXApICU+JSBzdW1tYXJpc2UobnVtX3BwID0gc3VtKG51bV9wcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fcGUgPSBzdW0obnVtX3BlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bV9wcyA9IHN1bShudW1fcHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3B4ID0gc3VtKG51bV9weCkpCgoKbG9vcFR5cGVMb25nIDwtIGxvb3BUeXBlICU+JSBwaXZvdF9sb25nZXIoLWdyb3VwLCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gImNvdW50IikKCmxvb3BUeXBlTG9uZyR0eXBlIDwtIGZhY3Rvcihsb29wVHlwZUxvbmckdHlwZSwgbGV2ZWxzID0gYygibnVtX3BwIiwgIm51bV9wZSIsICJudW1fcHMiLCAibnVtX3B4IikpCgojIFBsb3R0aW5nCmdncGxvdChsb29wVHlwZUxvbmcsIGFlcyhmaWxsPXR5cGUsIHk9Y291bnQsIHg9Z3JvdXApKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiLCBzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpCgpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtUApgYGB7cn0KIyMjIyMjIyMKI1AtUApkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcHApCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKIyBwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgYnkgPSAyKSwgbGltaXRzID0gYygwLCA1KSkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAzLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNTogIiwgcHYyNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfQTQ4NV92c19ETVNPX3BwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtRQpgYGB7cn0KIyMjIyMjIyMKI1AtRQpkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcGUpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKIyBwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgYnkgPSAyKSwgbGltaXRzID0gYygwLCA1KSkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAzLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNTogIiwgcHYyNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfQTQ4NV92c19ETVNPX3BlIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtUwpgYGB7cn0KIyMjIyMjIyMKI1AtUwpkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcHMpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKIyBwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgYnkgPSAyKSwgbGltaXRzID0gYygwLCA1KSkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAzLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNTogIiwgcHYyNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxKSsgIAoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfQTQ4NV92c19ETVNPX3BzIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIC0gTG9vcCBudW1iZXIgcGVyIGdlbmU6IFAtWApgYGB7cn0KIyMjIyMjIyMKI1AtWApkYXRhIDwtIHRlbXAyICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBudW1fcHgpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImdyb3VwIiwgImNvdW50IikKIyBwdjEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQojIHB2MTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiMgcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwMSIsICJncm91cDgiKSwgNSkKIyBwdjI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YSwiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLCJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiMgcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEsImdyb3VwNSIsICJncm91cDgiKSwgNSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBjb3VudCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArICAgICAgIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNSwgYnkgPSAyKSwgbGltaXRzID0gYygwLCA1KSkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAzLCBsYWJlbCA9IHBhc3RlMCgicHYxMjogIiwgcHYxMiwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxNTogIiwgcHYxNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNTogIiwgcHYyNSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgcHYyOCwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAxKSsgIAoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRfYmFycGxvdF9kaWZmR3JvdXBfQTQ4NV92c19ETVNPX3B4IikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyMgZFRBRwojIyMjIEdyb3VwaW5nIHdpdGggUC1OIG51bWJlcgojIyMjIyBHcm91cGluZwpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CmRpZmYuUFJPLkcxLmRUQUcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxRzIuZFRBR19HMS5kVEFHX3ZzX0cxLkRNU09fUFJPc2VxLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSwgYWJzKHNocmlua2VkX2xvZzJGQykgPiBmY0N1dG9mZikKZGlmZi5QUk8uRzIuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzFHMi5kVEFHX0cyLmRUQUdfdnNfRzIuRE1TT19QUk9zZXEudHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgYWxwaGEsIGFicyhzaHJpbmtlZF9sb2cyRkMpID4gZmNDdXRvZmYpCmRpZmYuUk5BLkcxLmRUQUcubm9GQ2N1dG9mZiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhKQojIyMjIyMjIyMjIyMKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCgoKIyB0ZW1wMiBjb250YWlucyBnZW5lcyBmcm9tIGdyb3VwIDEsIDIsIDUsIDggYW5kIGxvb3AgY291bnRzCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCnJlc3VsdERpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQiKQoKdGVtcDIgPC0gcmVhZFJEUyhoZXJlKHJlc3VsdERpciwgImdlbmVfbG9vcF9saW5rLnJkcyIpKQoKCnBuT3ZlcjggPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDgpKSRnZW5lCnBuT3ZlcjYgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDYsIHRvdGFsIDwgOCkpJGdlbmUKcG5PdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gNCwgdG90YWwgPCA2KSkkZ2VuZQpwbk92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcih0b3RhbCA+PSAyLCB0b3RhbCA8IDQpKSRnZW5lCnBuT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsIDwgMikpJGdlbmUKCgoKIyMgRGl2aWRpbmcgZ2VuZXMgaW50byBncm91cHMKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9kVEFHX0RNU08sIGRpc3RhbmNlLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX2RUQUdfRE1TTyksCiAgICAgICAgICAgIG1lYW5fZGlzdGFuY2UgPSBtZWFuKGRpc3RhbmNlKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykKCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCm1heExvZzJGQyA9IDIKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBkaWZmLlJOQS5HMS5kVEFHJGVuc2VtYmxfZ2VuZV9pZCwgIjJET1dOIiwgIjBOTyIpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpICU+JQogIGRyb3BfbmEoc2hyaW5rZWRfbG9nMkZDKQoKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6bXV0YXRlKAogIHBuT3ZlciA9IGlmZWxzZShnZW5lICVpbiUgcG5PdmVyOCwgInBuT3ZlcjgiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBuT3ZlcjYsICJwbk92ZXI2IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcG5PdmVyNCwgInBuT3ZlcjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcG5PdmVyMiwgInBuT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBuT3ZlcjAsICJwbk92ZXIwIiwgTkEpKSkpKSkgJT4lCiAgZHJvcF9uYShwbk92ZXIpCmBgYAoKIyMjIyMgR08gZm9yIGVhY2ggZ3JvdXAKYGBge3J9CkdPZmlnRGlyIDwtIGhlcmUoZmlnRGlyLCAiLi4vR08iKQpnZXRHTygicG5PdmVyOCIsIEdPZmlnRGlyLCBwbk92ZXI4KQpnZXRHTygicG5PdmVyNiIsIEdPZmlnRGlyLCBwbk92ZXI2KQpnZXRHTygicG5PdmVyNCIsIEdPZmlnRGlyLCBwbk92ZXI0KQpnZXRHTygicG5PdmVyMiIsIEdPZmlnRGlyLCBwbk92ZXIyKQpnZXRHTygicG5PdmVyMCIsIEdPZmlnRGlyLCBwbk92ZXIwKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCkdPMC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXIwLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCkdPMi5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXIyLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCkdPNC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXI0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCkdPNi5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXI2LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCkdPOC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXI4LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCgoKc3Vic2V0MCA8LSBHTzAuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwbk92ZXIwIikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKc3Vic2V0MiA8LSBHTzIuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwbk92ZXIyIikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKc3Vic2V0NCA8LSBHTzQuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwbk92ZXI0IikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKc3Vic2V0NiA8LSBHTzYuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwbk92ZXI2IikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKc3Vic2V0OCA8LSBHTzguZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwbk92ZXI4IikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKCgpHT2xpc3QgPC0gZmFjdG9yKGMoIkdPOjAwMDYzOTciLCAiR086MDAwODM4MCIsICJHTzowMDIyNjEzIiwgIkdPOjAwMzQ0NzAiLAogICAgICAgICAgICAgICAgICAgIkdPOjAwMTYwNTUiLCAiR086MDAwNzM4OSIsICJHTzowMDQ4NTYyIiwgIkdPOjAwNDUxNjUiLCAKICAgICAgICAgICAgICAgICAgICJHTzowMDcyMDAxIiwgIkdPOjAwMDc1MTciLCAiR086MDA0ODcwNSIpKQoKZGF0YSA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKGJpbmRfcm93cyhzdWJzZXQwLCBzdWJzZXQyKSwgc3Vic2V0NCksIHN1YnNldDgpICU+JQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gRGVzY3JpcHRpb24sIGNvbG9yID0gcC5hZGp1c3QsIHNpemUgPSBncikpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gInJlZCIsIGhpZ2ggPSAiYmx1ZSIsIGxpbWl0cyA9IGMoMCwgMC4wNSkpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDMpKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgYXhpcyB0aXRsZSBzaXplIChpZiBub3QgcmVtb3ZlZCkKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BuIikKaGVpZ2h0ID0gMgp3aWR0aCA9IDMuMwpzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgoKIyMjIyMgbG9vcCBzY29yZQpgYGB7cn0KZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMSkgKSRtZWFuX2RpZmZfc2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocG5PdmVyID09Z3JvdXAyKSApJG1lYW5fZGlmZl9zY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnB2MDIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMCIsICJwbk92ZXIyIiksIDUpCnB2MjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMiIsICJwbk92ZXI0IiksIDUpCnB2NDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyNCIsICJwbk92ZXI2IiksIDUpCnB2MDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMCIsICJwbk92ZXI4IiksIDUpCnB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMiIsICJwbk92ZXI4IiksIDUpCnB2NDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyNCIsICJwbk92ZXI4IiksIDUpCnB2NjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyNiIsICJwbk92ZXI4IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwbk92ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcG5PdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwbk92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC4yKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwYXN0ZTAoInB2MDI6ICIsIGNvbnZQdmFsdWUocHYwMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI0OiAiLCBjb252UHZhbHVlKHB2MjQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0NjogIiwgY29udlB2YWx1ZShwdjQ2KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2Njg6ICIsIGNvbnZQdmFsdWUocHY2OCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjQ4OiAiLCBjb252UHZhbHVlKHB2NDgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgY29udlB2YWx1ZShwdjI4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MDg6ICIsIGNvbnZQdmFsdWUocHYwOCksICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImRpZmZTY29yZV9iYXJwbG90X3BuR3JvdXBfZFRBR192c19ETVNPIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIGxvZzJGQwpgYGB7cn0KIwogZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMSkgKSRsb2cyRm9sZENoYW5nZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwbk92ZXIgPT1ncm91cDIpICkkbG9nMkZvbGRDaGFuZ2UKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9Cgp0ZW1wRG93biA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKIApwdjAyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwbk92ZXIwIiwgInBuT3ZlcjIiKSwgNSkKcHYwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicG5PdmVyMCIsICJwbk92ZXI0IiksIDUpCnB2MDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjAiLCAicG5PdmVyNiIpLCA1KQpwdjA4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwbk92ZXIwIiwgInBuT3ZlcjgiKSwgNSkKcHYyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicG5PdmVyMiIsICJwbk92ZXI0IiksIDUpCnB2MjYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjIiLCAicG5PdmVyNiIpLCA1KQpwdjI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwbk92ZXIyIiwgInBuT3ZlcjgiKSwgNSkKcHY0NiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicG5PdmVyNCIsICJwbk92ZXI2IiksIDUpCnB2NDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjQiLCAicG5PdmVyOCIpLCA1KQpwdjY4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwbk92ZXI2IiwgInBuT3ZlcjgiKSwgNSkKCgoKCnAgPC0gZ2dwbG90KHRlbXBEb3duLCBhZXMoeCA9IHBuT3ZlciwgeSA9IGxvZzJGb2xkQ2hhbmdlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBuT3ZlciksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gcG5PdmVyKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAtMC41LCBsYWJlbCA9IHBhc3RlMCgicHYwMjogIiwgY29udlB2YWx1ZShwdjAyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MDQ6ICIsIGNvbnZQdmFsdWUocHYwNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjA2OiAiLCBjb252UHZhbHVlKHB2MDYpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwODogIiwgY29udlB2YWx1ZShwdjA4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjQ6ICIsIGNvbnZQdmFsdWUocHYyNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI2OiAiLCBjb252UHZhbHVlKHB2MjYpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgY29udlB2YWx1ZShwdjI4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NDY6ICIsIGNvbnZQdmFsdWUocHY0NiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjQ4OiAiLCBjb252UHZhbHVlKHB2NDgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY2ODogIiwgY29udlB2YWx1ZShwdjY4KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEsIDApKQoKICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfYmFycGxvdF9wbkdyb3VwX2RUQUdfdnNfRE1TT19kb3duIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCgp0ZW1wVXAgPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApCiAKcHYwMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjAiLCAicG5PdmVyMiIpLCA1KQpwdjA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyMCIsICJwbk92ZXI0IiksIDUpCnB2MDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXIwIiwgInBuT3ZlcjYiKSwgNSkKcHYwOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjAiLCAicG5PdmVyOCIpLCA1KQpwdjI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyMiIsICJwbk92ZXI0IiksIDUpCnB2MjYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXIyIiwgInBuT3ZlcjYiKSwgNSkKcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjIiLCAicG5PdmVyOCIpLCA1KQpwdjQ2IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyNCIsICJwbk92ZXI2IiksIDUpCnB2NDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXI0IiwgInBuT3ZlcjgiKSwgNSkKcHY2OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjYiLCAicG5PdmVyOCIpLCA1KQoKCgoKcCA8LSBnZ3Bsb3QodGVtcFVwLCBhZXMoeCA9IHBuT3ZlciwgeSA9IGxvZzJGb2xkQ2hhbmdlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBuT3ZlciksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gcG5PdmVyKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLjUsIGxhYmVsID0gcGFzdGUwKCJwdjAyOiAiLCBjb252UHZhbHVlKHB2MDIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwNDogIiwgY29udlB2YWx1ZShwdjA0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MDY6ICIsIGNvbnZQdmFsdWUocHYwNiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjA4OiAiLCBjb252UHZhbHVlKHB2MDgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNDogIiwgY29udlB2YWx1ZShwdjI0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjY6ICIsIGNvbnZQdmFsdWUocHYyNiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBjb252UHZhbHVlKHB2MjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0NjogIiwgY29udlB2YWx1ZShwdjQ2KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2NDg6ICIsIGNvbnZQdmFsdWUocHY0OCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjY4OiAiLCBjb252UHZhbHVlKHB2NjgpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxKSkKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2JhcnBsb3RfcG5Hcm91cF9kVEFHX3ZzX0RNU09fdXAiKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyBHcm91cGluZyB3aXRoIFAtUyBudW1iZXIKIyMjIyMgR3JvdXBpbmcKYGBge3J9CiMgdGVtcDIgY29udGFpbnMgZ2VuZXMgZnJvbSBncm91cCAxLCAyLCA1LCA4IGFuZCBsb29wIGNvdW50cwojY2FsY3VsYXRpbmcgZGlmZiBzY29yZSBhbmQgbG9nMmZjIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBwLW4gbnVtYmVycwoKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAzLCBudW1fcHMgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMiwgbnVtX3BzIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDEsIG51bV9wcyA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA8IDEpKSRnZW5lCgoKCiMjIERpdmlkaW5nIGdlbmVzIGludG8gZ3JvdXBzCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfZFRBR19ETVNPLCBkaXN0YW5jZSwgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9kVEFHX0RNU08pLAogICAgICAgICAgICBtZWFuX2Rpc3RhbmNlID0gbWVhbihkaXN0YW5jZSksCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCgptYXhMb2cyRkMgPSAyCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZGlmZi5STkEuRzEuZFRBRyRlbnNlbWJsX2dlbmVfaWQsICIyRE9XTiIsICIwTk8iKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgbG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKSAlPiUKICBkcm9wX25hKHNocmlua2VkX2xvZzJGQykKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZSgKICBwc092ZXIgPSBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjQsICJwc092ZXI0IiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIzLCAicHNPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjIsICJwc092ZXIyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjEsICJwc092ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIwLCAicHNPdmVyMCIsIE5BKSkpKSkpICU+JQogIGRyb3BfbmEocHNPdmVyKQoKYGBgCgojIyMjIyBHTyBmb3IgZWFjaCBncm91cApgYGB7cn0KR09maWdEaXIgPC0gaGVyZShmaWdEaXIsICIuLi9HTyIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMKR08wLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjAsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiLCByZWFkYWJsZSA9IFRSVUUpKQpHTzEuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMSwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCkdPMi5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIyLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIiwgcmVhZGFibGUgPSBUUlVFKSkKR08zLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiLCByZWFkYWJsZSA9IFRSVUUpKQpHTzQuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyNCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCgpmd3JpdGUoR08wLmRmLCBoZXJlKCJHT19QU19ncm91cDAudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZShHTzEuZGYsIGhlcmUoIkdPX1BTX2dyb3VwMS50c3YiKSwgc2VwID0gIlx0IikKZndyaXRlKEdPMi5kZiwgaGVyZSgiR09fUFNfZ3JvdXAyLnRzdiIpLCBzZXAgPSAiXHQiKQpmd3JpdGUoR08zLmRmLCBoZXJlKCJHT19QU19ncm91cDMudHN2IiksIHNlcCA9ICJcdCIpCmZ3cml0ZShHTzQuZGYsIGhlcmUoIkdPX1BTX2dyb3VwNC50c3YiKSwgc2VwID0gIlx0IikKCkdPMC5kZiA8LSBmcmVhZChoZXJlKCJHT19QU19ncm91cDAudHN2IikpCkdPMS5kZiA8LSBmcmVhZChoZXJlKCJHT19QU19ncm91cDEudHN2IikpCkdPMi5kZiA8LSBmcmVhZChoZXJlKCJHT19QU19ncm91cDIudHN2IikpCkdPMy5kZiA8LSBmcmVhZChoZXJlKCJHT19QU19ncm91cDMudHN2IikpCkdPNC5kZiA8LSBmcmVhZChoZXJlKCJHT19QU19ncm91cDQudHN2IikpCgpzdWJzZXQwIDwtIEdPMC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDAiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0MSA8LSBHTzEuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCAxIikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCnN1YnNldDIgPC0gR08yLmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiR3JvdXAgMiIpICU+JQogIGRwbHlyOjphcnJhbmdlKHAuYWRqdXN0KQpzdWJzZXQzIDwtIEdPMy5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDMiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0NCA8LSBHTzQuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCA0IikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCgpzdWJzZXQwJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MCRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQxJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MSRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQyJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MiRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQzJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MyRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQ0JEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0NCRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQoKCkdPbGlzdCA8LSBmYWN0b3IoYygiR086MDAwODM4MCIsICJHTzowMDA2Mzk3IiwgIkdPOjAwMzQ0NzAiLCAiR086MDAyMjYxMyIsICJHTzowMDE2MDU1IiwKICAgICAgICAgICAgICAgICAgICJHTzowMDYxMTM4IiwgIkdPOjAwNjA1NjIiLCAiR086MDAwNzM4OSIsICJHTzowMDYwNDg1IiwgIkdPOjAwNDg2MzgiLCAiR086MDA0NTY2NCIpKQoKZGF0YSA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKGJpbmRfcm93cyhiaW5kX3Jvd3Moc3Vic2V0MCwgc3Vic2V0MSksIHN1YnNldDIpLCBzdWJzZXQzKSwgc3Vic2V0NCkgJT4lCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIEdPbGlzdCkKCmRlc2NPcmRlciA8LSBzb3J0KHVuaXF1ZShkYXRhJERlc2NyaXB0aW9uKSlbcmV2KGMoMTAsIDQsIDUsIDksIDExLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIsIDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMywgMSwgOCwgNykpXQoKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6cm93d2lzZSgpICU+JSBkcGx5cjo6bXV0YXRlKHBWYWx1ZUxvZyA9IG1pbigtbG9nMTAocC5hZGp1c3QpLCBwVmFsdWVMb2dNYXgpKQpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gZmFjdG9yKERlc2NyaXB0aW9uLCBsZXZlbHMgPSBkZXNjT3JkZXIpLCBzaXplID0gcFZhbHVlTG9nLCBmaWxsID0gR2VuZVJhdGlvKSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsICAgICAgICAjIEVuc3VyZXMgYSBwb2ludCB3aXRoIGFuIG91dGxpbmUKICAgICAgICAgICAgIHN0cm9rZSA9IDEqcHRUb01NKSArIAogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMC41LCAyKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgIG9vYiA9IHNjYWxlczo6c3F1aXNoLCAjIERlZmluZSBncmFkaWVudCBjb2xvcnMKICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIoCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gMS41LzUuMDgsICAjIEFkanVzdCB3aWR0aCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IDE1LzUuMDggICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgKQogICkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwogIHRoZW1lX2J3KCkgKyAgIyBBcHBseSB0aGVtZV9idyBmaXJzdCwgc28gY3VzdG9tIHRoZW1lIHNldHRpbmdzIGNvbWUgYWZ0ZXIKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLCAgIyBPdmVycmlkZSB0aGVtZV9idyBwYW5lbAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsICAgICAgICAgIyBFbnN1cmUgc2l6ZSBpcyBzZXQgZm9yIHgtYXhpcyB0ZXh0CiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgICAgICAgICAjIEVuc3VyZSBzaXplIGlzIHNldCBmb3IgeS1heGlzIHRleHQKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBsaW5laGVpZ2h0ID0gMC45ICAgICAgICAgICMgQWxsb3dzIHdyYXBwaW5nIGZvciB5LWF4aXMgbGFiZWxzIHRvIGZpdCBpbnRvIDIgbGluZXMKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BzIikKd2lkdGggPC0gcGFuZWxTaXplKDIuNykqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCnN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIGxvb3Agc2NvcmUKYGBge3J9CmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDEpICkkbWVhbl9kaWZmX3Njb3JlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMikgKSRtZWFuX2RpZmZfc2NvcmUKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgpwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyMSIpLCA1KQpwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQpwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjMiLCAicHNPdmVyNCIpLCA1KQpwczI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjIiLCAicHNPdmVyNCIpLCA1KQpwczE0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQpwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gcHNPdmVyLCB5ID0gbWVhbl9kaWZmX3Njb3JlKSkgKyAKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBzT3ZlciksIAogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJBdmVyYWdlIM6UIGxvb3Agc2NvcmUiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gcHNPdmVyKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMC41LCAwLjEpKQoKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImRpZmZTY29yZV9iYXJwbG90X3BzR3JvdXBfZFRBR192c19ETVNPXzIiKQp3aWR0aCA8LSAzMyptbVRvSW5jaApoZWlnaHQgPC0zMyptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIGxvZzJGQwpgYGB7cn0KdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6bXV0YXRlKGFic0xvZzJGQyA9IGFicyhsb2cyRm9sZENoYW5nZSkpCgprc19yZXN1bHQxIDwtIGtzLnRlc3QoCiAgdGVtcCAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT0gInBzT3ZlcjQiKSAlPiUgcHVsbChhYnNMb2cyRkMpLAogIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09ICJwc092ZXIzIikgJT4lIHB1bGwoYWJzTG9nMkZDKQopCmtzX3Jlc3VsdDIgPC0ga3MudGVzdCgKICB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PSAicHNPdmVyNCIpICU+JSBwdWxsKGFic0xvZzJGQyksCiAgdGVtcCAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT0gInBzT3ZlcjIiKSAlPiUgcHVsbChhYnNMb2cyRkMpCikKa3NfcmVzdWx0MyA8LSBrcy50ZXN0KAogIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09ICJwc092ZXI0IikgJT4lIHB1bGwoYWJzTG9nMkZDKSwKICB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PSAicHNPdmVyMSIpICU+JSBwdWxsKGFic0xvZzJGQykKKQprc19yZXN1bHQ0IDwtIGtzLnRlc3QoCiAgdGVtcCAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT0gInBzT3ZlcjQiKSAlPiUgcHVsbChhYnNMb2cyRkMpLAogIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09ICJwc092ZXIwIikgJT4lIHB1bGwoYWJzTG9nMkZDKQopCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGFic0xvZzJGQywgY29sb3IgPSBwc092ZXIpKSArCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAoYygiIzc3Nzc3NyIsICIjOEI3RTY1IiwgIiNBMjg0NTIiLCAiI0MyODg0RCIsICIjRjI4RTJDIikpKSArCiAgc3RhdF9lY2RmKHNpemUgPSAwLjQsIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiApICsgIyBVc2Ugc3RhdF9lY2RmIHRvIHBsb3QgdGhlIGVtcGlyaWNhbCBDREYKICBsYWJzKAogICAgeCA9ICJBYnMuIGxvZzIoZm9sZCBjaGFuZ2UpIiwKICAgIHkgPSAiQ3VtdWxhdGl2ZSBQcm9iYWJpbGl0eSIKICApICsgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEuNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKyAjIENsZWFuIHRoZW1lCiAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xKSkKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfY2RmX3BzR3JvdXBfZFRBR192c19ETVNPIikKd2lkdGggPC0gMzMqbW1Ub0luY2gKaGVpZ2h0IDwtMzMqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKCiMKIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDEpICkkbG9nMkZvbGRDaGFuZ2UKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJGxvZzJGb2xkQ2hhbmdlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKdGVtcERvd24gPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDApCiAKcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCnBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQpwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKcHMzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCnBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjIiLCAicHNPdmVyNCIpLCA1KQpwczE0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKCnBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQoKCnAgPC0gZ2dwbG90KHRlbXBEb3duLCBhZXMoeCA9IHBzT3ZlciwgeSA9IGxvZzJGb2xkQ2hhbmdlKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRDlEOUQ5IiwgIiNCRkJGQkYiLCAiI0E2QTZBNiIsICIjOEM4QzhDIiwgIiM3MzczNzMiKSkgKyAjIEZpdmUgc2hhZGVzIG9mIGdyZXkKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBzT3ZlciksIAogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEKICApICsgdGhlbWVfY2xhc3NpYygpICsgbGFicyh4ID0gTlVMTCAsIHkgPSAibG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gcHNPdmVyKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAtMC41LCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxNDogIiwgY29udlB2YWx1ZShwczE0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLCAwKSkKICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfYmFycGxvdF9wc0dyb3VwX2RUQUdfdnNfRE1TT19kb3duIikKd2lkdGggPC0gcGFuZWxTaXplKDEuMikqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxKSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCgp0ZW1wVXAgPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApCiAKcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjAiLCAicHNPdmVyMSIpLCA1KQpwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCnBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKcHMzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjMiLCAicHNPdmVyNCIpLCA1KQpwczI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCnBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKcHMwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQoKCgoKcCA8LSBnZ3Bsb3QodGVtcFVwLCBhZXMoeCA9IHBzT3ZlciwgeSA9IGxvZzJGb2xkQ2hhbmdlKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRDlEOUQ5IiwgIiNCRkJGQkYiLCAiI0E2QTZBNiIsICIjOEM4QzhDIiwgIiM3MzczNzMiKSkgKyAjIEZpdmUgc2hhZGVzIG9mIGdyZXkKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBzT3ZlciksIAogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEKICApICsgdGhlbWVfY2xhc3NpYygpICsgbGFicyh4ID0gTlVMTCAsIHkgPSAibG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gcHNPdmVyKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLjUsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczE0OiAiLCBjb252UHZhbHVlKHBzMTQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMwNDogIiwgY29udlB2YWx1ZShwczA0KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMSkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BzR3JvdXBfZFRBR192c19ETVNPX3VwIikKd2lkdGggPC0gcGFuZWxTaXplKDEuMTgpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMSkqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgoKIyMjIyBHcm91cGluZyB3aXRoIFAtRSBudW1iZXIKIyMjIyMgR3JvdXBpbmcKYGBge3J9CiMgdGVtcDIgY29udGFpbnMgZ2VuZXMgZnJvbSBncm91cCAxLCAyLCA1LCA4IGFuZCBsb29wIGNvdW50cwojY2FsY3VsYXRpbmcgZGlmZiBzY29yZSBhbmQgbG9nMmZjIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBwLW4gbnVtYmVycwoKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAzLCBudW1fcGUgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMiwgbnVtX3BlIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDEsIG51bV9wZSA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA8IDEpKSRnZW5lCgoKCiMjIERpdmlkaW5nIGdlbmVzIGludG8gZ3JvdXBzCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfZFRBR19ETVNPLCBkaXN0YW5jZSwgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9kVEFHX0RNU08pLAogICAgICAgICAgICBtZWFuX2Rpc3RhbmNlID0gbWVhbihkaXN0YW5jZSksCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCgptYXhMb2cyRkMgPSAyCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZmxhZyA9IGlmZWxzZShnZW5lICVpbiUgZGlmZi5STkEuRzEuZFRBRyRlbnNlbWJsX2dlbmVfaWQsICIyRE9XTiIsICIwTk8iKSwKICAgICAgICAgICAgICAgIG1heEZsYWcgPSAoYWJzKHNocmlua2VkX2xvZzJGQykgPiBtYXhMb2cyRkMpLAogICAgICAgICAgICAgICAgbG9nMmZjTWF4ID0gcG1heChwbWluKHNocmlua2VkX2xvZzJGQywgbWF4TG9nMkZDKSwgLW1heExvZzJGQykpICU+JSAKICBkcGx5cjo6YXJyYW5nZShmbGFnKSAlPiUKICBkcm9wX25hKHNocmlua2VkX2xvZzJGQykKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZSgKICBwc092ZXIgPSBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjQsICJwc092ZXI0IiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIzLCAicHNPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjIsICJwc092ZXIyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjEsICJwc092ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIwLCAicHNPdmVyMCIsIE5BKSkpKSkpICU+JQogIGRyb3BfbmEocHNPdmVyKQoKYGBgCgojIyMjIyBHTyBmb3IgZWFjaCBncm91cApgYGB7cn0KR09maWdEaXIgPC0gaGVyZShmaWdEaXIsICIuLi9HTyIpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwpHTzAuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCkdPMS5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIxLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIiwgcmVhZGFibGUgPSBUUlVFKSkKR08yLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjIsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiLCByZWFkYWJsZSA9IFRSVUUpKQpHTzMuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMywgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCkdPNC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXI0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIiwgcmVhZGFibGUgPSBUUlVFKSkKCiMgZndyaXRlKEdPMC5kZiwgaGVyZSgiR09fUEVfZ3JvdXAwLnRzdiIpLCBzZXAgPSAiXHQiKQojIGZ3cml0ZShHTzEuZGYsIGhlcmUoIkdPX1BFX2dyb3VwMS50c3YiKSwgc2VwID0gIlx0IikKIyBmd3JpdGUoR08yLmRmLCBoZXJlKCJHT19QRV9ncm91cDIudHN2IiksIHNlcCA9ICJcdCIpCiMgZndyaXRlKEdPMy5kZiwgaGVyZSgiR09fUEVfZ3JvdXAzLnRzdiIpLCBzZXAgPSAiXHQiKQojIGZ3cml0ZShHTzQuZGYsIGhlcmUoIkdPX1BFX2dyb3VwNC50c3YiKSwgc2VwID0gIlx0IikKCgpzdWJzZXQwIDwtIEdPMC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDAiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0MSA8LSBHTzEuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCAxIikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCnN1YnNldDIgPC0gR08yLmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiR3JvdXAgMiIpICU+JQogIGRwbHlyOjphcnJhbmdlKHAuYWRqdXN0KQpzdWJzZXQzIDwtIEdPMy5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDMiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0NCA8LSBHTzQuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCA0IikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCgpzdWJzZXQwJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MCRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQxJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MSRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQyJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MiRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQzJEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0MyRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQpzdWJzZXQ0JEdlbmVSYXRpbyA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0NCRHZW5lUmF0aW8sICIvIiksIGZ1bmN0aW9uKHgpIGFzLm51bWVyaWMoeFsxXSkgLyBhcy5udW1lcmljKHhbMl0pKQoKR09saXN0IDwtIGZhY3RvcihjKCJHTzowMDA4MzgwIiwgIkdPOjAwMDYzOTciLCAiR086MDAzNDQ3MCIsICJHTzowMDIyNjEzIiwgIkdPOjAwMTYwNTUiLAogICAgICAgICAgICAgICAgICAgIkdPOjAwNjExMzgiLCAiR086MDA2MDU2MiIsICJHTzowMDA3Mzg5IiwgIkdPOjAwNjA0ODUiLCAiR086MDA0ODYzOCIsICJHTzowMDQ1NjY0IiwKICAgICAgICAgICAgICAgICAgICJHTzowMDQwMDI5IikpCgpkYXRhIDwtIGJpbmRfcm93cyhiaW5kX3Jvd3MoYmluZF9yb3dzKHN1YnNldDAsIHN1YnNldDEpLCBzdWJzZXQyKSwgc3Vic2V0NCkgJT4lCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIEdPbGlzdCkKCmRlc2NPcmRlciA8LSBzb3J0KHVuaXF1ZShkYXRhJERlc2NyaXB0aW9uKSlbcmV2KGMoMTEsIDUsIDYsIDEwLCAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMsIDcsIDQsIDIsIDksIDgpKV0KCmVtcHR5X3JvdzMgPC0gZGF0YS5mcmFtZSgKICBJRCA9IE5BLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBObyBzcGVjaWZpYyBJRAogIERlc2NyaXB0aW9uID0gTkEsICAgICAgICAgICAgICAgICAgICAjIE5vIGRlc2NyaXB0aW9uCiAgR2VuZVJhdGlvID0gTkEsICAgICAgICAgICAgICAgICAgICAgICMgTm8gZ2VuZSByYXRpbwogIHAuYWRqdXN0ID0gTkEsICAgICAgICAgICAgICAgICAgICAgICAjIE5vIHAuYWRqdXN0IHZhbHVlCiAgZ3JvdXAgPSAiR3JvdXAgMyIgICAgICAgICAgICAgICAgICAgIyBHcm91cCB0byBhZGQgYXMgZW1wdHkgY29sdW1uCikKCmVtcHR5X3JvdzQgPC0gZGF0YS5mcmFtZSgKICBJRCA9IE5BLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBObyBzcGVjaWZpYyBJRAogIERlc2NyaXB0aW9uID0gTkEsICAgICAgICAgICAgICAgICAgICAjIE5vIGRlc2NyaXB0aW9uCiAgR2VuZVJhdGlvID0gTkEsICAgICAgICAgICAgICAgICAgICAgICMgTm8gZ2VuZSByYXRpbwogIHAuYWRqdXN0ID0gTkEsICAgICAgICAgICAgICAgICAgICAgICAjIE5vIHAuYWRqdXN0IHZhbHVlCiAgZ3JvdXAgPSAiR3JvdXAgNCIgICAgICAgICAgICAgICAgICAgIyBHcm91cCB0byBhZGQgYXMgZW1wdHkgY29sdW1uCikKCiMgQXBwZW5kIHRoZSBlbXB0eSByb3cgdG8geW91ciBkYXRhc2V0CmRhdGEgPC0gcmJpbmQoZGF0YSwgZW1wdHlfcm93MywgZW1wdHlfcm93NCkKCgpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUocFZhbHVlTG9nID0gbWluKC1sb2cxMChwLmFkanVzdCksIHBWYWx1ZUxvZ01heCkpCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBmYWN0b3IoRGVzY3JpcHRpb24sIGxldmVscyA9IGRlc2NPcmRlciksIHNpemUgPSBwVmFsdWVMb2csIGZpbGwgPSBHZW5lUmF0aW8pKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgICAgICAgICMgRW5zdXJlcyBhIHBvaW50IHdpdGggYW4gb3V0bGluZQogICAgICAgICAgICAgc3Ryb2tlID0gMSpwdFRvTU0pICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjUsIDIpKSArICAjIFNldCBtaW4gYW5kIG1heCBwb2ludCBzaXplcyBoZXJlCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiNDQjMzM0EiLAogICAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDAsIDEpLAogICAgICAgICAgICAgICAgICAgICAgb29iID0gc2NhbGVzOjpzcXVpc2gsICMgRGVmaW5lIGdyYWRpZW50IGNvbG9ycwogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICMgQWRqdXN0IGhlaWdodCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICApCiAgKSArIAogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgdGhlbWVfYncoKSArICAjIEFwcGx5IHRoZW1lX2J3IGZpcnN0LCBzbyBjdXN0b20gdGhlbWUgc2V0dGluZ3MgY29tZSBhZnRlcgogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksICAjIE92ZXJyaWRlIHRoZW1lX2J3IHBhbmVsCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgICAgICAgICAjIEVuc3VyZSBzaXplIGlzIHNldCBmb3IgeC1heGlzIHRleHQKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCAgICAgICAgICMgRW5zdXJlIHNpemUgaXMgc2V0IGZvciB5LWF4aXMgdGV4dAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIGxpbmVoZWlnaHQgPSAwLjkgICAgICAgICAgIyBBbGxvd3Mgd3JhcHBpbmcgZm9yIHktYXhpcyBsYWJlbHMgdG8gZml0IGludG8gMiBsaW5lcwogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKQoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsICIuLiIsICJHTyIsICJHT19ncm91cHNfcGUiKQp3aWR0aCA8LSBwYW5lbFNpemUoMi42NSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjMpKm1tVG9JbmNoCnN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKIyMjIyMgbG9vcCBzY29yZQpgYGB7cn0KZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMSkgKSRtZWFuX2RpZmZfc2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJG1lYW5fZGlmZl9zY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCnBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCnBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMiIsICJwc092ZXIzIiksIDUpCnBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCnBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCnBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMSIsICJwc092ZXI0IiksIDUpCnBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwc092ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzc3Nzc3NyIsICIjOEI3RTY1IiwgIiNBMjg0NTIiLCAiI0MyODg0RCIsICIjRjI4RTJDIikpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBzT3ZlciksIAogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJBdmVyYWdlIM6UIGxvb3Agc2NvcmUiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gcHNPdmVyKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDAuMSkpCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJkaWZmU2NvcmVfYmFycGxvdF9wZUdyb3VwX2RUQUdfdnNfRE1TTyIpCndpZHRoIDwtIDMzKm1tVG9JbmNoCmhlaWdodCA8LTMzKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgbG9nMkZDCmBgYHtyfQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoYWJzTG9nMkZDID0gYWJzKGxvZzJGb2xkQ2hhbmdlKSkKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBhYnNMb2cyRkMsIGNvbG9yID0gcHNPdmVyKSkgKwpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gKGMoIiM3Nzc3NzciLCAiIzhCN0U2NSIsICIjQTI4NDUyIiwgIiNDMjg4NEQiLCAiI0YyOEUyQyIpKSkgKwogIHN0YXRfZWNkZihzaXplID0gMC40LCBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIgKSArICMgVXNlIHN0YXRfZWNkZiB0byBwbG90IHRoZSBlbXBpcmljYWwgQ0RGCiAgbGFicygKICAgIHggPSAiQWJzLiBsb2cyKGZvbGQgY2hhbmdlKSIsCiAgICB5ID0gIkN1bXVsYXRpdmUgUHJvYmFiaWxpdHkiCiAgKSArIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAxLjUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsgIyBDbGVhbiB0aGVtZQogIHRoZW1lKAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgICApICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSkpCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2NkZl9wZUdyb3VwX2RUQUdfdnNfRE1TTyIpCndpZHRoIDwtIDMzKm1tVG9JbmNoCmhlaWdodCA8LTMzKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIwogZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMSkgKSRsb2cyRm9sZENoYW5nZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDIpICkkbG9nMkZvbGRDaGFuZ2UKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9Cgp0ZW1wRG93biA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKIApwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIwIiwgInBzT3ZlcjEiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCnBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIzIiwgInBzT3ZlcjQiKSwgNSkKcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCnBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQoKcHMwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcERvd24sIGFlcyh4ID0gcHNPdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArICMgRml2ZSBzaGFkZXMgb2YgZ3JleQogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcHNPdmVyKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJsb2cyKGZvbGQgY2hhbmdlKSIpICsKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBwc092ZXIpLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAxLAogICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IC0wLjUsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczE0OiAiLCBjb252UHZhbHVlKHBzMTQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMwNDogIiwgY29udlB2YWx1ZShwczA0KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEsIDApKQogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BlR3JvdXBfZFRBR192c19ETVNPX2Rvd24iKQp3aWR0aCA8LSBwYW5lbFNpemUoMS4yKSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCnRlbXBVcCA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCkKIApwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCnBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIxIiwgInBzT3ZlcjIiKSwgNSkKcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCnBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIyIiwgInBzT3ZlcjQiKSwgNSkKcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQpwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKCgpwIDwtIGdncGxvdCh0ZW1wVXAsIGFlcyh4ID0gcHNPdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArICMgRml2ZSBzaGFkZXMgb2YgZ3JleQogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcHNPdmVyKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJsb2cyKGZvbGQgY2hhbmdlKSIpICsKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBwc092ZXIpLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAxLAogICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxKSkKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2JhcnBsb3RfcGVHcm91cF9kVEFHX3ZzX0RNU09fdXAiKQp3aWR0aCA8LSBwYW5lbFNpemUoMS4xOCkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxKSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyMjIEdyb3VwaW5nIHdpdGggUC1QIG51bWJlcgojIyMjIyBHcm91cGluZwpgYGB7cn0KIyB0ZW1wMiBjb250YWlucyBnZW5lcyBmcm9tIGdyb3VwIDEsIDIsIDUsIDggYW5kIGxvb3AgY291bnRzCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCgpwc092ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gNCkpJGdlbmUKcHNPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDMsIG51bV9wcCA8IDQpKSRnZW5lCnBzT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAyLCBudW1fcHAgPCAzKSkkZ2VuZQpwc092ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMSwgbnVtX3BwIDwgMikpJGdlbmUKcHNPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwIDwgMSkpJGdlbmUKCgoKIyMgRGl2aWRpbmcgZ2VuZXMgaW50byBncm91cHMKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9kVEFHX0RNU08sIGRpc3RhbmNlLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX2RUQUdfRE1TTyksCiAgICAgICAgICAgIG1lYW5fZGlzdGFuY2UgPSBtZWFuKGRpc3RhbmNlKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykKCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLjJpLmRUQUdfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCm1heExvZzJGQyA9IDIKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShmbGFnID0gaWZlbHNlKGdlbmUgJWluJSBkaWZmLlJOQS5HMS5kVEFHJGVuc2VtYmxfZ2VuZV9pZCwgIjJET1dOIiwgIjBOTyIpLAogICAgICAgICAgICAgICAgbWF4RmxhZyA9IChhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IG1heExvZzJGQyksCiAgICAgICAgICAgICAgICBsb2cyZmNNYXggPSBwbWF4KHBtaW4oc2hyaW5rZWRfbG9nMkZDLCBtYXhMb2cyRkMpLCAtbWF4TG9nMkZDKSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGZsYWcpICU+JQogIGRyb3BfbmEoc2hyaW5rZWRfbG9nMkZDKQoKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6bXV0YXRlKAogIHBzT3ZlciA9IGlmZWxzZShnZW5lICVpbiUgcHNPdmVyNCwgInBzT3ZlcjQiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjMsICJwc092ZXIzIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHNPdmVyMiwgInBzT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHNPdmVyMSwgInBzT3ZlcjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBzT3ZlcjAsICJwc092ZXIwIiwgTkEpKSkpKSkgJT4lCiAgZHJvcF9uYShwc092ZXIpCgoKYGBgCiMjIyMjIEdPIGZvciBlYWNoIGdyb3VwCmBgYHtyfQpHT2ZpZ0RpciA8LSBoZXJlKGZpZ0RpciwgIi4uL0dPIikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwpHTzAuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCkdPMS5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIxLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIiwgcmVhZGFibGUgPSBUUlVFKSkKR08yLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjIsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiLCByZWFkYWJsZSA9IFRSVUUpKQpHTzMuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMywgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIsIHJlYWRhYmxlID0gVFJVRSkpCkdPNC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXI0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIiwgcmVhZGFibGUgPSBUUlVFKSkKIyAKIyBmd3JpdGUoR08wLmRmLCBoZXJlKCJHT19QUF9ncm91cDAudHN2IiksIHNlcCA9ICJcdCIpCiMgZndyaXRlKEdPMS5kZiwgaGVyZSgiR09fUFBfZ3JvdXAxLnRzdiIpLCBzZXAgPSAiXHQiKQojIGZ3cml0ZShHTzIuZGYsIGhlcmUoIkdPX1BQX2dyb3VwMi50c3YiKSwgc2VwID0gIlx0IikKIyBmd3JpdGUoR08zLmRmLCBoZXJlKCJHT19QUF9ncm91cDMudHN2IiksIHNlcCA9ICJcdCIpCiMgZndyaXRlKEdPNC5kZiwgaGVyZSgiR09fUFBfZ3JvdXA0LnRzdiIpLCBzZXAgPSAiXHQiKQoKc3Vic2V0MCA8LSBHTzAuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCAwIikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCnN1YnNldDEgPC0gR08xLmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiR3JvdXAgMSIpICU+JQogIGRwbHlyOjphcnJhbmdlKHAuYWRqdXN0KQpzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkdyb3VwIDIiKSAlPiUKICBkcGx5cjo6YXJyYW5nZShwLmFkanVzdCkKc3Vic2V0MyA8LSBHTzMuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHcm91cCAzIikgJT4lCiAgZHBseXI6OmFycmFuZ2UocC5hZGp1c3QpCnN1YnNldDQgPC0gR080LmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiR3JvdXAgNCIpICU+JQogIGRwbHlyOjphcnJhbmdlKHAuYWRqdXN0KQoKc3Vic2V0MCRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDAkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKc3Vic2V0MSRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDEkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKc3Vic2V0MiRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDIkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKc3Vic2V0MyRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDMkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKc3Vic2V0NCRHZW5lUmF0aW8gPC0gc2FwcGx5KHN0cnNwbGl0KHN1YnNldDQkR2VuZVJhdGlvLCAiLyIpLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHhbMV0pIC8gYXMubnVtZXJpYyh4WzJdKSkKCkdPbGlzdCA8LSBmYWN0b3IoYygiR086MDAwODM4MCIsICJHTzowMDA2Mzk3IiwgIkdPOjAwMzQ0NzAiLCAiR086MDAyMjYxMyIsICJHTzowMDE2MDU1IiwKICAgICAgICAgICAgICAgICAgICJHTzowMDYxMTM4IiwgIkdPOjAwNjA1NjIiLCAiR086MDAwNzM4OSIsICJHTzowMDYwNDg1IiwgIkdPOjAwNDg2MzgiLCAiR086MDA0NTY2NCIpKQoKZGF0YSA8LSBiaW5kX3Jvd3Moc3Vic2V0MCwgc3Vic2V0MSkgJT4lCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIEdPbGlzdCkKCgoKZW1wdHlfcm93MiA8LSBkYXRhLmZyYW1lKAogIElEID0gTkEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5vIHNwZWNpZmljIElECiAgRGVzY3JpcHRpb24gPSBOQSwgICAgICAgICAgICAgICAgICAgICMgTm8gZGVzY3JpcHRpb24KICBHZW5lUmF0aW8gPSBOQSwgICAgICAgICAgICAgICAgICAgICAgIyBObyBnZW5lIHJhdGlvCiAgcC5hZGp1c3QgPSBOQSwgICAgICAgICAgICAgICAgICAgICAgICMgTm8gcC5hZGp1c3QgdmFsdWUKICBncm91cCA9ICJHcm91cCAyIiAgICAgICAgICAgICAgICAgICAjIEdyb3VwIHRvIGFkZCBhcyBlbXB0eSBjb2x1bW4KKQoKZW1wdHlfcm93MyA8LSBkYXRhLmZyYW1lKAogIElEID0gTkEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5vIHNwZWNpZmljIElECiAgRGVzY3JpcHRpb24gPSBOQSwgICAgICAgICAgICAgICAgICAgICMgTm8gZGVzY3JpcHRpb24KICBHZW5lUmF0aW8gPSBOQSwgICAgICAgICAgICAgICAgICAgICAgIyBObyBnZW5lIHJhdGlvCiAgcC5hZGp1c3QgPSBOQSwgICAgICAgICAgICAgICAgICAgICAgICMgTm8gcC5hZGp1c3QgdmFsdWUKICBncm91cCA9ICJHcm91cCAzIiAgICAgICAgICAgICAgICAgICAjIEdyb3VwIHRvIGFkZCBhcyBlbXB0eSBjb2x1bW4KKQoKZW1wdHlfcm93NCA8LSBkYXRhLmZyYW1lKAogIElEID0gTkEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5vIHNwZWNpZmljIElECiAgRGVzY3JpcHRpb24gPSBOQSwgICAgICAgICAgICAgICAgICAgICMgTm8gZGVzY3JpcHRpb24KICBHZW5lUmF0aW8gPSBOQSwgICAgICAgICAgICAgICAgICAgICAgIyBObyBnZW5lIHJhdGlvCiAgcC5hZGp1c3QgPSBOQSwgICAgICAgICAgICAgICAgICAgICAgICMgTm8gcC5hZGp1c3QgdmFsdWUKICBncm91cCA9ICJHcm91cCA0IiAgICAgICAgICAgICAgICAgICAjIEdyb3VwIHRvIGFkZCBhcyBlbXB0eSBjb2x1bW4KKQoKIyBBcHBlbmQgdGhlIGVtcHR5IHJvdyB0byB5b3VyIGRhdGFzZXQKZGF0YSA8LSByYmluZChkYXRhLCBlbXB0eV9yb3cyLCBlbXB0eV9yb3czLCBlbXB0eV9yb3c0KQpkZXNjT3JkZXIgPC0gc29ydCh1bmlxdWUoZGF0YSREZXNjcmlwdGlvbikpW3JldihjKDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDQsIDUsIDksIDExLCAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMiwgNiwgMywgMSwgOCwgNykpXQpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoRGVzY3JpcHRpb24gJWluJSBkZXNjT3JkZXIpCgoKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6cm93d2lzZSgpICU+JSBkcGx5cjo6bXV0YXRlKHBWYWx1ZUxvZyA9IG1pbigtbG9nMTAocC5hZGp1c3QpLCBwVmFsdWVMb2dNYXgpKQpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gZmFjdG9yKERlc2NyaXB0aW9uLCBsZXZlbHMgPSBkZXNjT3JkZXIpLCBzaXplID0gcFZhbHVlTG9nLCBmaWxsID0gR2VuZVJhdGlvKSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsICAgICAgICAjIEVuc3VyZXMgYSBwb2ludCB3aXRoIGFuIG91dGxpbmUKICAgICAgICAgICAgIHN0cm9rZSA9IDEqcHRUb01NKSArIAogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMC41LCAyKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgIG9vYiA9IHNjYWxlczo6c3F1aXNoLCAjIERlZmluZSBncmFkaWVudCBjb2xvcnMKICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIoCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gMS41LzUuMDgsICAjIEFkanVzdCB3aWR0aCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IDE1LzUuMDggICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgKQogICkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwogIHRoZW1lX2J3KCkgKyAgIyBBcHBseSB0aGVtZV9idyBmaXJzdCwgc28gY3VzdG9tIHRoZW1lIHNldHRpbmdzIGNvbWUgYWZ0ZXIKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLCAgIyBPdmVycmlkZSB0aGVtZV9idyBwYW5lbAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsICAgICAgICAgIyBFbnN1cmUgc2l6ZSBpcyBzZXQgZm9yIHgtYXhpcyB0ZXh0CiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgICAgICAgICAjIEVuc3VyZSBzaXplIGlzIHNldCBmb3IgeS1heGlzIHRleHQKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBsaW5laGVpZ2h0ID0gMC45ICAgICAgICAgICMgQWxsb3dzIHdyYXBwaW5nIGZvciB5LWF4aXMgbGFiZWxzIHRvIGZpdCBpbnRvIDIgbGluZXMKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BwIikKd2lkdGggPC0gcGFuZWxTaXplKDIuNjUpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS4yKSptbVRvSW5jaApzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyBsb29wIHNjb3JlCmBgYHtyfQpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAxKSApJG1lYW5fZGlmZl9zY29yZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDIpICkkbWVhbl9kaWZmX3Njb3JlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIwIiwgInBzT3ZlcjEiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIxIiwgInBzT3ZlcjIiKSwgNSkKcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKcHMzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIzIiwgInBzT3ZlcjQiKSwgNSkKcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjQiKSwgNSkKcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKcHMwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIwIiwgInBzT3ZlcjQiKSwgNSkKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gcHNPdmVyLCB5ID0gbWVhbl9kaWZmX3Njb3JlKSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHJldihjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBzT3ZlciksIAogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJBdmVyYWdlIM6UIGxvb3Agc2NvcmUiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gcHNPdmVyKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIgogICkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDAuMSkpCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJkaWZmU2NvcmVfYmFycGxvdF9wcEdyb3VwX2RUQUdfdnNfRE1TTyIpCndpZHRoIDwtIDMzKm1tVG9JbmNoCmhlaWdodCA8LTMzKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgpgYGAKIyMjIyMgbG9nMkZDCmBgYHtyfQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoYWJzTG9nMkZDID0gYWJzKGxvZzJGb2xkQ2hhbmdlKSkKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBhYnNMb2cyRkMsIGNvbG9yID0gcHNPdmVyKSkgKwpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gKHJldihjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkpKSArCiAgc3RhdF9lY2RmKHNpemUgPSAwLjQsIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiApICsgIyBVc2Ugc3RhdF9lY2RmIHRvIHBsb3QgdGhlIGVtcGlyaWNhbCBDREYKICBsYWJzKAogICAgeCA9ICJBYnMuIGxvZzIoZm9sZCBjaGFuZ2UpIiwKICAgIHkgPSAiQ3VtdWxhdGl2ZSBQcm9iYWJpbGl0eSIKICApICsgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEuNSkpICsKICB0aGVtZV9jbGFzc2ljKCkgKyAjIENsZWFuIHRoZW1lCiAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xKSkKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfY2RmX3BwR3JvdXBfZFRBR192c19ETVNPIikKd2lkdGggPC0gMzMqbW1Ub0luY2gKaGVpZ2h0IDwtMzMqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKIwogZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMSkgKSRsb2cyRm9sZENoYW5nZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDIpICkkbG9nMkZvbGRDaGFuZ2UKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9Cgp0ZW1wRG93biA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKIApwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIwIiwgInBzT3ZlcjEiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCnBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIzIiwgInBzT3ZlcjQiKSwgNSkKcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCnBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQoKcHMwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcERvd24sIGFlcyh4ID0gcHNPdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArICMgRml2ZSBzaGFkZXMgb2YgZ3JleQogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcHNPdmVyKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJsb2cyKGZvbGQgY2hhbmdlKSIpICsKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBwc092ZXIpLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAxLAogICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IC0wLjUsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczE0OiAiLCBjb252UHZhbHVlKHBzMTQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMwNDogIiwgY29udlB2YWx1ZShwczA0KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEsIDApKQogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BwR3JvdXBfZFRBR192c19ETVNPX2Rvd24iKQp3aWR0aCA8LSBwYW5lbFNpemUoMS4yKSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCnRlbXBVcCA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCkKIApwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCnBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIxIiwgInBzT3ZlcjIiKSwgNSkKcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCnBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIyIiwgInBzT3ZlcjQiKSwgNSkKcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQpwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKCgpwIDwtIGdncGxvdCh0ZW1wVXAsIGFlcyh4ID0gcHNPdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArICMgRml2ZSBzaGFkZXMgb2YgZ3JleQogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcHNPdmVyKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQQogICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHggPSBOVUxMICwgeSA9ICJsb2cyKGZvbGQgY2hhbmdlKSIpICsKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBwc092ZXIpLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAxLAogICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxKSkKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2JhcnBsb3RfcHBHcm91cF9kVEFHX3ZzX0RNU09fdXAiKQp3aWR0aCA8LSBwYW5lbFNpemUoMS4xOCkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxKSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyBBNDg1CiMjIyMgR3JvdXBpbmcgd2l0aCBQLU4gbnVtYmVyCiMjIyMjIEdyb3VwaW5nCmBgYHtyfQojIyMjIyMjIyMjIyMKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCgojIHRlbXAyCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCnRlbXAyIDwtIHJlYWRSRFMoaGVyZShyZXN1bHREaXIsICJnZW5lX2xvb3BfbGlua19BNDg1LnJkcyIpKQoKcG5PdmVyOCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gOCkpJGdlbmUKcG5PdmVyNiA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gNiwgdG90YWwgPCA4KSkkZ2VuZQpwbk92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcih0b3RhbCA+PSA0LCB0b3RhbCA8IDYpKSRnZW5lCnBuT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDIsIHRvdGFsIDwgNCkpJGdlbmUKcG5PdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPCAyKSkkZ2VuZQoKCgojIyBEaXZpZGluZyBnZW5lcyBpbnRvIGdyb3Vwcwp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZGlzdGFuY2UsIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfQTQ4NV9ETVNPKSwKICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oZGlzdGFuY2UpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLjJpLkE0ODVfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCm1heExvZzJGQyA9IDIKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHJvcF9uYShzaHJpbmtlZF9sb2cyRkMpCgp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoCiAgcG5PdmVyID0gaWZlbHNlKGdlbmUgJWluJSBwbk92ZXI4LCAicG5PdmVyOCIsCiAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcG5PdmVyNiwgInBuT3ZlcjYiLAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwbk92ZXI0LCAicG5PdmVyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwbk92ZXIyLCAicG5PdmVyMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcG5PdmVyMCwgInBuT3ZlcjAiLCBOQSkpKSkpKSAlPiUKICBkcm9wX25hKHBuT3ZlcikKYGBgCgojIyMjIyAoU0tJUCkgR08gZm9yIGVhY2ggZ3JvdXAKYGBge3J9CiMgR09maWdEaXIgPC0gaGVyZShmaWdEaXIsICIuLi9HTyIpCiMgZ2V0R08oInBuT3ZlcjgiLCBHT2ZpZ0RpciwgcG5PdmVyOCkKIyBnZXRHTygicG5PdmVyNiIsIEdPZmlnRGlyLCBwbk92ZXI2KQojIGdldEdPKCJwbk92ZXI0IiwgR09maWdEaXIsIHBuT3ZlcjQpCiMgZ2V0R08oInBuT3ZlcjIiLCBHT2ZpZ0RpciwgcG5PdmVyMikKIyBnZXRHTygicG5PdmVyMCIsIEdPZmlnRGlyLCBwbk92ZXIwKQojIAojICMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEdPMC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXIwLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR08yLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBuT3ZlcjIsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyBHTzQuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcG5PdmVyNCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQojIEdPNi5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwbk92ZXI2LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR084LmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBuT3ZlcjgsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyAKIyAKIyBzdWJzZXQwIDwtIEdPMC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBuT3ZlcjAiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBuT3ZlcjIiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQ0IDwtIEdPNC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBuT3ZlcjQiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQ2IDwtIEdPNi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBuT3ZlcjYiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQ4IDwtIEdPOC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBuT3ZlcjgiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyAKIyAKIyBHT2xpc3QgPC0gZmFjdG9yKGMoIkdPOjAwMDYzOTciLCAiR086MDAwODM4MCIsICJHTzowMDIyNjEzIiwgIkdPOjAwMzQ0NzAiLAojICAgICAgICAgICAgICAgICAgICAiR086MDAxNjA1NSIsICJHTzowMDA3Mzg5IiwgIkdPOjAwNDg1NjIiLCAiR086MDA0NTE2NSIsIAojICAgICAgICAgICAgICAgICAgICAiR086MDA3MjAwMSIsICJHTzowMDA3NTE3IiwgIkdPOjAwNDg3MDUiKSkKIyAKIyBkYXRhIDwtIGJpbmRfcm93cyhiaW5kX3Jvd3MoYmluZF9yb3dzKHN1YnNldDAsIHN1YnNldDIpLCBzdWJzZXQ0KSwgc3Vic2V0OCkgJT4lCiMgICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgR09saXN0KQojIAojIHAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBEZXNjcmlwdGlvbiwgY29sb3IgPSBwLmFkanVzdCwgc2l6ZSA9IGdyKSkgKyAKIyAgIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKwojICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gInJlZCIsIGhpZ2ggPSAiYmx1ZSIsIGxpbWl0cyA9IGMoMCwgMC4wNSkpICsKIyAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgMykpICsKIyAgIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiMgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKIyAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBheGlzIHRpdGxlIHNpemUgKGlmIG5vdCByZW1vdmVkKQojICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBsZWdlbmQgdGV4dCBzaXplCiMgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKIyAKIyBmaWxlTmFtZSA8LSBoZXJlKGZpZ0RpciwgIi4uIiwgIkdPIiwgIkdPX2dyb3Vwc19wbiIpCiMgaGVpZ2h0ID0gMgojIHdpZHRoID0gMy4zCiMgc3ZnbGl0ZShwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIiksIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKIyBwcmludChwKQojIGRldi5vZmYoKQpgYGAKCgojIyMjIyBsb29wIHNjb3JlCmBgYHtyfQojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMSkgKSRtZWFuX2RpZmZfc2NvcmUKIyAgIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwbk92ZXIgPT1ncm91cDIpICkkbWVhbl9kaWZmX3Njb3JlCiMgICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiMgICByZXR1cm4od2lsJHAudmFsdWUpCiMgfQojIAojIHB2MDIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMCIsICJwbk92ZXIyIiksIDUpCiMgcHYyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwbk92ZXIyIiwgInBuT3ZlcjQiKSwgNSkKIyBwdjQ2IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBuT3ZlcjQiLCAicG5PdmVyNiIpLCA1KQojIHB2MDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyMCIsICJwbk92ZXI4IiksIDUpCiMgcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwbk92ZXIyIiwgInBuT3ZlcjgiKSwgNSkKIyBwdjQ4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBuT3ZlcjQiLCAicG5PdmVyOCIpLCA1KQojIHB2NjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicG5PdmVyNiIsICJwbk92ZXI4IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwbk92ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcG5PdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwbk92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHBhc3RlMCgicHYwMjogIiwgY29udlB2YWx1ZShwdjAyKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNDogIiwgY29udlB2YWx1ZShwdjI0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0NjogIiwgY29udlB2YWx1ZShwdjQ2KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY2ODogIiwgY29udlB2YWx1ZShwdjY4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0ODogIiwgY29udlB2YWx1ZShwdjQ4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgY29udlB2YWx1ZShwdjI4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwODogIiwgY29udlB2YWx1ZShwdjA4KSwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQoKICAgCmZpbGVOYW1lIDwtIHBhc3RlMCgiZGlmZlNjb3JlX2JhcnBsb3RfcG5Hcm91cF9BNDg1X3ZzX0RNU08iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgbG9nMkZDCmBgYHtyfQojCiMgIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMSkgKSRsb2cyRm9sZENoYW5nZQojICAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMikgKSRsb2cyRm9sZENoYW5nZQojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KIyAKdGVtcERvd24gPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDApCiMgIAojIHB2MDIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjAiLCAicG5PdmVyMiIpLCA1KQojIHB2MDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjAiLCAicG5PdmVyNCIpLCA1KQojIHB2MDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjAiLCAicG5PdmVyNiIpLCA1KQojIHB2MDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjAiLCAicG5PdmVyOCIpLCA1KQojIHB2MjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjIiLCAicG5PdmVyNCIpLCA1KQojIHB2MjYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjIiLCAicG5PdmVyNiIpLCA1KQojIHB2MjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjIiLCAicG5PdmVyOCIpLCA1KQojIHB2NDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjQiLCAicG5PdmVyNiIpLCA1KQojIHB2NDggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjQiLCAicG5PdmVyOCIpLCA1KQojIHB2NjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBuT3ZlcjYiLCAicG5PdmVyOCIpLCA1KQoKCgoKcCA8LSBnZ3Bsb3QodGVtcERvd24sIGFlcyh4ID0gcG5PdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcG5PdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwbk92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAtMC41LCBsYWJlbCA9IHBhc3RlMCgicHYwMjogIiwgY29udlB2YWx1ZShwdjAyKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwNDogIiwgY29udlB2YWx1ZShwdjA0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwNjogIiwgY29udlB2YWx1ZShwdjA2KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYwODogIiwgY29udlB2YWx1ZShwdjA4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNDogIiwgY29udlB2YWx1ZShwdjI0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyNjogIiwgY29udlB2YWx1ZShwdjI2KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYyODogIiwgY29udlB2YWx1ZShwdjI4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0NjogIiwgY29udlB2YWx1ZShwdjQ2KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY0ODogIiwgY29udlB2YWx1ZShwdjQ4KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY2ODogIiwgY29udlB2YWx1ZShwdjY4KSwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMSwgMCkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BuR3JvdXBfQTQ4NV92c19ETVNPX2Rvd24iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCnRlbXBVcCA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCkKIyAgCiMgcHYwMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjAiLCAicG5PdmVyMiIpLCA1KQojIHB2MDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXIwIiwgInBuT3ZlcjQiKSwgNSkKIyBwdjA2IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyMCIsICJwbk92ZXI2IiksIDUpCiMgcHYwOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjAiLCAicG5PdmVyOCIpLCA1KQojIHB2MjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXIyIiwgInBuT3ZlcjQiKSwgNSkKIyBwdjI2IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyMiIsICJwbk92ZXI2IiksIDUpCiMgcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjIiLCAicG5PdmVyOCIpLCA1KQojIHB2NDYgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwbk92ZXI0IiwgInBuT3ZlcjYiKSwgNSkKIyBwdjQ4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicG5PdmVyNCIsICJwbk92ZXI4IiksIDUpCiMgcHY2OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBuT3ZlcjYiLCAicG5PdmVyOCIpLCA1KQojIAoKCgpwIDwtIGdncGxvdCh0ZW1wVXAsIGFlcyh4ID0gcG5PdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcG5PdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwbk92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLjUsIGxhYmVsID0gcGFzdGUwKCJwdjAyOiAiLCBjb252UHZhbHVlKHB2MDIpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjA0OiAiLCBjb252UHZhbHVlKHB2MDQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjA2OiAiLCBjb252UHZhbHVlKHB2MDYpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjA4OiAiLCBjb252UHZhbHVlKHB2MDgpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI0OiAiLCBjb252UHZhbHVlKHB2MjQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI2OiAiLCBjb252UHZhbHVlKHB2MjYpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBjb252UHZhbHVlKHB2MjgpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjQ2OiAiLCBjb252UHZhbHVlKHB2NDYpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjQ4OiAiLCBjb252UHZhbHVlKHB2NDgpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjY4OiAiLCBjb252UHZhbHVlKHB2NjgpLCAiXG4iKSwgCiAgIyAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDEpKQoKICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfYmFycGxvdF9wbkdyb3VwX0E0ODVfdnNfRE1TT191cCIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIEdyb3VwaW5nIHdpdGggUC1TIG51bWJlcgojIyMjIyBHcm91cGluZwpgYGB7cn0KIyB0ZW1wMiBjb250YWlucyBnZW5lcyBmcm9tIGdyb3VwIDEsIDIsIDUsIDggYW5kIGxvb3AgY291bnRzCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCgpwc092ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gNCkpJGdlbmUKcHNPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDMsIG51bV9wcyA8IDQpKSRnZW5lCnBzT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAyLCBudW1fcHMgPCAzKSkkZ2VuZQpwc092ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMSwgbnVtX3BzIDwgMikpJGdlbmUKcHNPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzIDwgMSkpJGdlbmUKCgoKCiMjIERpdmlkaW5nIGdlbmVzIGludG8gZ3JvdXBzCnRlbXAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6c2VsZWN0KGRpZmZfQTQ4NV9ETVNPLCBkaXN0YW5jZSwgZ2VuZSkgJT4lIAogIHVubmVzdChnZW5lKSAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGlmZl9zY29yZSA9IG1lYW4oZGlmZl9BNDg1X0RNU08pLAogICAgICAgICAgICBtZWFuX2Rpc3RhbmNlID0gbWVhbihkaXN0YW5jZSksCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuMmkuQTQ4NV92c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQoKbWF4TG9nMkZDID0gMgoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcm9wX25hKHNocmlua2VkX2xvZzJGQykKCgp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoCiAgcHNPdmVyID0gaWZlbHNlKGdlbmUgJWluJSBwc092ZXI0LCAicHNPdmVyNCIsCiAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHNPdmVyMywgInBzT3ZlcjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIyLCAicHNPdmVyMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwc092ZXIxLCAicHNPdmVyMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHNPdmVyMCwgInBzT3ZlcjAiLCBOQSkpKSkpKSAlPiUKICBkcm9wX25hKHBzT3ZlcikKCmBgYAoKIyMjIyMgKFNLSVApIEdPIGZvciBlYWNoIGdyb3VwCmBgYHtyfQojIEdPZmlnRGlyIDwtIGhlcmUoZmlnRGlyLCAiLi4vR08iKQojIGdldEdPKCJwc092ZXI0IiwgR09maWdEaXIsIHBzT3ZlcjQpCiMgZ2V0R08oInBzT3ZlcjMiLCBHT2ZpZ0RpciwgcHNPdmVyMykKIyBnZXRHTygicHNPdmVyMiIsIEdPZmlnRGlyLCBwc092ZXIyKQojIGdldEdPKCJwc092ZXIxIiwgR09maWdEaXIsIHBzT3ZlcjEpCiMgZ2V0R08oInBzT3ZlcjAiLCBHT2ZpZ0RpciwgcHNPdmVyMCkKIyAKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBHTzAuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQojIEdPMS5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIxLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR08yLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjIsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyBHTzMuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMywgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQojIEdPNC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXI0LCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgCiMgCiMgc3Vic2V0MCA8LSBHTzAuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwc092ZXIwIikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgc3Vic2V0MSA8LSBHTzEuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwc092ZXIxIikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgc3Vic2V0MiA8LSBHTzIuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwc092ZXIyIikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgc3Vic2V0MyA8LSBHTzMuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwc092ZXIzIikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgc3Vic2V0NCA8LSBHTzQuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJwc092ZXI0IikgJT4lCiMgICBkcGx5cjo6bXV0YXRlKAojICAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKIyAgICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiMgICAgICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHgsICIvIikpCiMgICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiMgICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQojICAgICB9KQojICAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCiMgCiMgCiMgR09saXN0IDwtIGZhY3RvcihjKCJHTzowMDA2Mzk3IiwgIkdPOjAwMDgzODAiLCAiR086MDAyMjYxMyIsICJHTzowMDM0NDcwIiwKIyAgICAgICAgICAgICAgICAgICAgIkdPOjAwMTYwNTUiLCAiR086MDAwNzM4OSIsICJHTzowMDQ4NTYyIiwgIkdPOjAwNDUxNjUiLCAKIyAgICAgICAgICAgICAgICAgICAgIkdPOjAwNzIwMDEiLCAiR086MDAwNzUxNyIsICJHTzowMDQ4NzA1IiwgIkdPOjAwMDMwMDIiKSkKIyAKIyBkYXRhIDwtIGJpbmRfcm93cyhiaW5kX3Jvd3MoYmluZF9yb3dzKGJpbmRfcm93cyhzdWJzZXQwLCBzdWJzZXQxKSwgc3Vic2V0MiksIHN1YnNldDMpLCBzdWJzZXQ0KSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCiMgCiMgcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IERlc2NyaXB0aW9uLCBjb2xvciA9IHAuYWRqdXN0LCBzaXplID0gZ3IpKSArIAojICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArCiMgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbGltaXRzID0gYygwLCAwLjA1KSkgKwojICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCAzKSkgKwojICAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsKIyAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICAjIFNldCBheGlzIHRleHQgc2l6ZQojICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGF4aXMgdGl0bGUgc2l6ZSAoaWYgbm90IHJlbW92ZWQpCiMgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKIyAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIAojIAojIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BzIikKIyBoZWlnaHQgPSAyCiMgd2lkdGggPSAzLjQKIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCmBgYAoKIyMjIyMgbG9vcCBzY29yZQpgYGB7cn0KIyBnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKIyAgIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDEpICkkbWVhbl9kaWZmX3Njb3JlCiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJG1lYW5fZGlmZl9zY29yZQojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KIyAKIyBwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyMSIpLCA1KQojIHBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCiMgcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKIyBwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjMiLCAicHNPdmVyNCIpLCA1KQojIHBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCiMgcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKIyBwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQojIAoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwc092ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcHNPdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwc092ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgiZGlmZlNjb3JlX2JhcnBsb3RfcHNHcm91cF9BNDg1X3ZzX0RNU08iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgbG9nMkZDCmBgYHtyfQojCiMgIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMSkgKSRsb2cyRm9sZENoYW5nZQojICAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMikgKSRsb2cyRm9sZENoYW5nZQojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KCnRlbXBEb3duIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPCAwKQojICAKIyBwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIwIiwgInBzT3ZlcjEiKSwgNSkKIyBwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIxIiwgInBzT3ZlcjIiKSwgNSkKIyBwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKIyBwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIzIiwgInBzT3ZlcjQiKSwgNSkKIyBwczI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIyIiwgInBzT3ZlcjQiKSwgNSkKIyBwczE0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKIyAKIyBwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcERvd24sICJwc092ZXIwIiwgInBzT3ZlcjQiKSwgNSkKCgpwIDwtIGdncGxvdCh0ZW1wRG93biwgYWVzKHggPSBwc092ZXIsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBwc092ZXIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHBzT3ZlciksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQogICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IC0wLjUsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczE0OiAiLCBjb252UHZhbHVlKHBzMTQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgIyAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLCAwKSkKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2JhcnBsb3RfcHNHcm91cF9BNDg1X3ZzX0RNU09fZG93biIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKdGVtcFVwIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPiAwKQojICAKIyBwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCiMgcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQojIHBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKIyBwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCiMgcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjIiLCAicHNPdmVyNCIpLCA1KQojIHBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKIyBwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCiMgCgoKCnAgPC0gZ2dwbG90KHRlbXBVcCwgYWVzKHggPSBwc092ZXIsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBwc092ZXIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHBzT3ZlciksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQogICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMSkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BzR3JvdXBfQTQ4NV92c19ETVNPX3VwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyMjIEdyb3VwaW5nIHdpdGggUC1FIG51bWJlcgojIyMjIyBHcm91cGluZwpgYGB7cn0KIyB0ZW1wMiBjb250YWlucyBnZW5lcyBmcm9tIGdyb3VwIDEsIDIsIDUsIDggYW5kIGxvb3AgY291bnRzCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCgpwZU92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gNCkpJGdlbmUKcGVPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDMsIG51bV9wZSA8IDQpKSRnZW5lCnBlT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAyLCBudW1fcGUgPCAzKSkkZ2VuZQpwZU92ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMSwgbnVtX3BlIDwgMikpJGdlbmUKcGVPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlIDwgMSkpJGdlbmUKCgoKIyMgRGl2aWRpbmcgZ2VuZXMgaW50byBncm91cHMKdGVtcCA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZGlmZl9BNDg1X0RNU08sIGRpc3RhbmNlLCBnZW5lKSAlPiUgCiAgdW5uZXN0KGdlbmUpICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUobWVhbl9kaWZmX3Njb3JlID0gbWVhbihkaWZmX0E0ODVfRE1TTyksCiAgICAgICAgICAgIG1lYW5fZGlzdGFuY2UgPSBtZWFuKGRpc3RhbmNlKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykKCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5BNDg1LnNlbGVjdGVkMl9HMS4yaS5BNDg1X3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCgptYXhMb2cyRkMgPSAyCgp0ZW1wIDwtIGxlZnRfam9pbih0ZW1wLCBkaWZmLlJOQSwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRyb3BfbmEoc2hyaW5rZWRfbG9nMkZDKQoKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZSgKICBwZU92ZXIgPSBpZmVsc2UoZ2VuZSAlaW4lIHBlT3ZlcjQsICJwZU92ZXI0IiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwZU92ZXIzLCAicGVPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBlT3ZlcjIsICJwZU92ZXIyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBlT3ZlcjEsICJwZU92ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwZU92ZXIwLCAicGVPdmVyMCIsIE5BKSkpKSkpICU+JQogIGRyb3BfbmEocGVPdmVyKQoKYGBgCgojIyMjIyAoU0tJUCkgR08gZm9yIGVhY2ggZ3JvdXAKYGBge3J9CiMgR09maWdEaXIgPC0gaGVyZShmaWdEaXIsICIuLi9HTyIpCiMgZ2V0R08oInBlT3ZlcjQiLCBHT2ZpZ0RpciwgcHNPdmVyNCkKIyBnZXRHTygicGVPdmVyMyIsIEdPZmlnRGlyLCBwc092ZXIzKQojIGdldEdPKCJwZU92ZXIyIiwgR09maWdEaXIsIHBzT3ZlcjIpCiMgZ2V0R08oInBlT3ZlcjEiLCBHT2ZpZ0RpciwgcHNPdmVyMSkKIyBnZXRHTygicGVPdmVyMCIsIEdPZmlnRGlyLCBwc092ZXIwKQojIAojICMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEdPMC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIwLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR08xLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjEsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyBHTzIuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMiwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQojIEdPMy5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIzLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR080LmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjQsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyAKIyAKIyBzdWJzZXQwIDwtIEdPMC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjAiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQxIDwtIEdPMS5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjEiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjIiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQzIDwtIEdPMy5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjMiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQ0IDwtIEdPNC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjQiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyAKIyAKIyBHT2xpc3QgPC0gZmFjdG9yKGMoIkdPOjAwMDYzOTciLCAiR086MDAwODM4MCIsICJHTzowMDIyNjEzIiwgIkdPOjAwMzQ0NzAiLAojICAgICAgICAgICAgICAgICAgICAiR086MDAxNjA1NSIsICJHTzowMDA3Mzg5IiwgIkdPOjAwNDg1NjIiLCAiR086MDA0NTE2NSIsIAojICAgICAgICAgICAgICAgICAgICAiR086MDA3MjAwMSIsICJHTzowMDA3NTE3IiwgIkdPOjAwNDg3MDUiLCAKIyAgICAgICAgICAgICAgICAgICAgIkdPOjAwNDAwMjkiLCAiR086MDAxMDE2NSIpKQojIAojIGRhdGEgPC0gYmluZF9yb3dzKGJpbmRfcm93cyhiaW5kX3Jvd3Moc3Vic2V0MCwgc3Vic2V0MSksIHN1YnNldDIpLCBzdWJzZXQ0KSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCiMgCiMgcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IERlc2NyaXB0aW9uLCBjb2xvciA9IHAuYWRqdXN0LCBzaXplID0gZ3IpKSArIAojICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArCiMgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbGltaXRzID0gYygwLCAwLjA1KSkgKwojICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCAzKSkgKwojICAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsKIyAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICAjIFNldCBheGlzIHRleHQgc2l6ZQojICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGF4aXMgdGl0bGUgc2l6ZSAoaWYgbm90IHJlbW92ZWQpCiMgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKIyAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIAojIAojIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BlIikKIyBoZWlnaHQgPSAyCiMgd2lkdGggPSAzLjQKIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCmBgYAojIyMjIyBsb29wIHNjb3JlCmBgYHtyfQojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBzT3ZlciA9PWdyb3VwMSkgKSRtZWFuX2RpZmZfc2NvcmUKIyAgIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDIpICkkbWVhbl9kaWZmX3Njb3JlCiMgICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiMgICByZXR1cm4od2lsJHAudmFsdWUpCiMgfQojIAojIHBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCiMgcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIxIiwgInBzT3ZlcjIiKSwgNSkKIyBwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQojIHBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCiMgcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjQiKSwgNSkKIyBwczE0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQojIHBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwZU92ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcGVPdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwZU92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxNDogIixjb252UHZhbHVlKCBwczE0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMwNDogIixjb252UHZhbHVlKCBwczA0KSwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQoKICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJkaWZmU2NvcmVfYmFycGxvdF9wZUdyb3VwX0E0ODVfdnNfRE1TTyIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyBsb2cyRkMKYGBge3J9CiMKIyAgZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiMgICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAxKSApJGxvZzJGb2xkQ2hhbmdlCiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJGxvZzJGb2xkQ2hhbmdlCiMgICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiMgICByZXR1cm4od2lsJHAudmFsdWUpCiMgfQojIAp0ZW1wRG93biA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKIyAgCiMgcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCiMgcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCiMgcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMiIsICJwc092ZXIzIiksIDUpCiMgcHMzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCiMgcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCiMgcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMSIsICJwc092ZXI0IiksIDUpCiMgcHMwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBEb3duLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcERvd24sIGFlcyh4ID0gcGVPdmVyLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcGVPdmVyKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBwZU92ZXIpLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKICAjIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAtMC41LCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyNDogIiwgY29udlB2YWx1ZShwczI0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxNDogIiwgY29udlB2YWx1ZShwczE0KSwgIlxuIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMwNDogIiwgY29udlB2YWx1ZShwczA0KSwgIlxuIiksIAogICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMSwgMCkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BlR3JvdXBfQTQ4NV92c19ETVNPX2Rvd24iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCnRlbXBVcCA8LSB0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCkKIAojIHBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIwIiwgInBzT3ZlcjEiKSwgNSkKIyBwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCiMgcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQojIHBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIzIiwgInBzT3ZlcjQiKSwgNSkKIyBwczI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCiMgcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQojIHBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIwIiwgInBzT3ZlcjQiKSwgNSkKIyAKCgoKCnAgPC0gZ2dwbG90KHRlbXBVcCwgYWVzKHggPSBwZU92ZXIsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBwZU92ZXIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHBlT3ZlciksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQogICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMSkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BlR3JvdXBfQTQ4NV92c19ETVNPX3VwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyMjIEdyb3VwaW5nIHdpdGggUC1QIG51bWJlcgojIyMjIyBHcm91cGluZwpgYGB7cn0KIyB0ZW1wMiBjb250YWlucyBnZW5lcyBmcm9tIGdyb3VwIDEsIDIsIDUsIDggYW5kIGxvb3AgY291bnRzCiNjYWxjdWxhdGluZyBkaWZmIHNjb3JlIGFuZCBsb2cyZmMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIHAtbiBudW1iZXJzCnBwT3ZlcjQgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSA0KSkkZ2VuZQpwcE92ZXIzIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMywgbnVtX3BwIDwgNCkpJGdlbmUKcHBPdmVyMiA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDIsIG51bV9wcCA8IDMpKSRnZW5lCnBwT3ZlcjEgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAxLCBudW1fcHAgPCAyKSkkZ2VuZQpwcE92ZXIwIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPCAxKSkkZ2VuZQoKCgojIyBEaXZpZGluZyBnZW5lcyBpbnRvIGdyb3Vwcwp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX0E0ODVfRE1TTywgZGlzdGFuY2UsIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfQTQ4NV9ETVNPKSwKICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oZGlzdGFuY2UpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLjJpLkE0ODVfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKCm1heExvZzJGQyA9IDIKCnRlbXAgPC0gbGVmdF9qb2luKHRlbXAsIGRpZmYuUk5BLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHJvcF9uYShzaHJpbmtlZF9sb2cyRkMpCgoKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6bXV0YXRlKAogIHBwT3ZlciA9IGlmZWxzZShnZW5lICVpbiUgcHBPdmVyNCwgInBwT3ZlcjQiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBwT3ZlcjMsICJwcE92ZXIzIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHBPdmVyMiwgInBwT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcHBPdmVyMSwgInBwT3ZlcjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIHBwT3ZlcjAsICJwcE92ZXIwIiwgTkEpKSkpKSkgJT4lCiAgZHJvcF9uYShwcE92ZXIpCmBgYAojIyMjIyAoU0tJUCkgR08gZm9yIGVhY2ggZ3JvdXAKYGBge3J9CiMgR09maWdEaXIgPC0gaGVyZShmaWdEaXIsICIuLi9HTyIpCiMgZ2V0R08oInBwT3ZlcjQiLCBHT2ZpZ0RpciwgcHNPdmVyNCkKIyBnZXRHTygicHBPdmVyMyIsIEdPZmlnRGlyLCBwc092ZXIzKQojIGdldEdPKCJwcE92ZXIyIiwgR09maWdEaXIsIHBzT3ZlcjIpCiMgZ2V0R08oInBwT3ZlcjEiLCBHT2ZpZ0RpciwgcHNPdmVyMSkKIyBnZXRHTygicHBPdmVyMCIsIEdPZmlnRGlyLCBwc092ZXIwKQojIAojICMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEdPMC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIwLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR08xLmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjEsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyBHTzIuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gcHNPdmVyMiwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQojIEdPMy5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBwc092ZXIzLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCiMgR080LmRmIDwtIGFzLmRhdGEuZnJhbWUoZW5yaWNoR08oZ2VuZSA9IHBzT3ZlcjQsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKIyAKIyAKIyBzdWJzZXQwIDwtIEdPMC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjAiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQxIDwtIEdPMS5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjEiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQyIDwtIEdPMi5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjIiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQzIDwtIEdPMy5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjMiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyBzdWJzZXQ0IDwtIEdPNC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gInBzT3ZlcjQiKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUoCiMgICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewojICAgICAgICMgU3BsaXQgdGhlIHN0cmluZyBieSAiLyIKIyAgICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKIyAgICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KIyAgICAgICBhcy5udW1lcmljKHBhcnRzWzFdKSAvIGFzLm51bWVyaWMocGFydHNbMl0pCiMgICAgIH0pCiMgICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKIyAKIyAKIyBHT2xpc3QgPC0gZmFjdG9yKGMoIkdPOjAwMDYzOTciLCAiR086MDAwODM4MCIsICJHTzowMDIyNjEzIiwgIkdPOjAwMzQ0NzAiLAojICAgICAgICAgICAgICAgICAgICAiR086MDAxNjA1NSIsICJHTzowMDA3Mzg5IiwgIkdPOjAwNDg1NjIiLCAiR086MDA0NTE2NSIsIAojICAgICAgICAgICAgICAgICAgICAiR086MDA3MjAwMSIsICJHTzowMDA3NTE3IiwgIkdPOjAwNDg3MDUiLCAiR086MDAwMzAwMiIsICJHTzowMDA5NDExIikpCiMgCiMgZGF0YSA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKHN1YnNldDAsIHN1YnNldDEpLCBzdWJzZXQzKSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBHT2xpc3QpCiMgCiMgcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IERlc2NyaXB0aW9uLCBjb2xvciA9IHAuYWRqdXN0LCBzaXplID0gZ3IpKSArIAojICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArCiMgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbGltaXRzID0gYygwLCAwLjA1KSkgKwojICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCAzKSkgKwojICAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsKIyAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICAjIFNldCBheGlzIHRleHQgc2l6ZQojICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGF4aXMgdGl0bGUgc2l6ZSAoaWYgbm90IHJlbW92ZWQpCiMgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKIyAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIAojIAojIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiLi4iLCAiR08iLCAiR09fZ3JvdXBzX3BwIikKIyBoZWlnaHQgPSAyCiMgd2lkdGggPSAzLjQKIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCmBgYAoKIyMjIyMgbG9vcCBzY29yZQpgYGB7cn0KIyBnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKIyAgIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihwc092ZXIgPT1ncm91cDEpICkkbWVhbl9kaWZmX3Njb3JlCiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJG1lYW5fZGlmZl9zY29yZQojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KIyAKIyBwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyMSIpLCA1KQojIHBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMSIsICJwc092ZXIyIiksIDUpCiMgcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKIyBwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjMiLCAicHNPdmVyNCIpLCA1KQojIHBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMiIsICJwc092ZXI0IiksIDUpCiMgcHMxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKIyBwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gcHBPdmVyLCB5ID0gbWVhbl9kaWZmX3Njb3JlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHBwT3ZlciksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gcHBPdmVyKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApCiAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgiZGlmZlNjb3JlX2JhcnBsb3RfcHBHcm91cF9BNDg1X3ZzX0RNU08iKQpoZWlnaHQgPC0gMwp3aWR0aCA8LSAzCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAojIyMjIyBsb2cyRkMKYGBge3J9CiMKIyAgZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiMgICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAxKSApJGxvZzJGb2xkQ2hhbmdlCiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocHNPdmVyID09Z3JvdXAyKSApJGxvZzJGb2xkQ2hhbmdlCiMgICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiMgICByZXR1cm4od2lsJHAudmFsdWUpCiMgfQoKdGVtcERvd24gPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihsb2cyRm9sZENoYW5nZSA8IDApCiMgIAojIHBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjAiLCAicHNPdmVyMSIpLCA1KQojIHBzMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQojIHBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjIiLCAicHNPdmVyMyIpLCA1KQojIHBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjMiLCAicHNPdmVyNCIpLCA1KQojIHBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjIiLCAicHNPdmVyNCIpLCA1KQojIHBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjEiLCAicHNPdmVyNCIpLCA1KQojIHBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wRG93biwgInBzT3ZlcjAiLCAicHNPdmVyNCIpLCA1KQoKCgpwIDwtIGdncGxvdCh0ZW1wRG93biwgYWVzKHggPSBwcE92ZXIsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBwcE92ZXIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHBwT3ZlciksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQogICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IC0wLjUsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczI0OiAiLCBjb252UHZhbHVlKHBzMjQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczE0OiAiLCBjb252UHZhbHVlKHBzMTQpLCAiXG4iLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczA0OiAiLCBjb252UHZhbHVlKHBzMDQpLCAiXG4iKSwgCiAgIyAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLCAwKSkKCiAgCmZpbGVOYW1lIDwtIHBhc3RlMCgibG9nMkZDX2JhcnBsb3RfcHBHcm91cF9BNDg1X3ZzX0RNU09fZG93biIpCmhlaWdodCA8LSAzCndpZHRoIDwtIDMKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKdGVtcFVwIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPiAwKQojICAKIyBwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCiMgcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQojIHBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKIyBwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCiMgcHMyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBVcCwgInBzT3ZlcjIiLCAicHNPdmVyNCIpLCA1KQojIHBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wVXAsICJwc092ZXIxIiwgInBzT3ZlcjQiKSwgNSkKIyBwczA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcFVwLCAicHNPdmVyMCIsICJwc092ZXI0IiksIDUpCiMgCiMgCgoKCnAgPC0gZ2dwbG90KHRlbXBVcCwgYWVzKHggPSBwcE92ZXIsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBwcE92ZXIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IHBwT3ZlciksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQogICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTQ6ICIsIGNvbnZQdmFsdWUocHMxNCksICJcbiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAjICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMSkpCgogIApmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19iYXJwbG90X3BwR3JvdXBfQTQ4NV92c19ETVNPX3VwIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIFsyLjEzXSBIb3cgdG8gZGVmaW5lIG11bHRpY29ubmVjdGVkIGh1YiB1c2luZyByZWd1bGF0b3J5IGxvb3BzPwpgYGB7cn0KIyBJTVBPUlRJTkcgR0VORSBBTk5PIERBVEEgRk9SIFAtTiBMT09QUwpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNiwgMTEsIDEyLCAxMywgMjIsIDIzLCAyNCwgMjUsIDI3LCAyOCkpCgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNiwgMTEsIDEyLCAxMywgMjIsIDIzLCAyNCwgMjUsIDI3KSkgJT4lCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gZW5kMSAtIHN0YXJ0MSwKICAgICAgICAgICAgICAgIGFkal9zdGFydDEgPSBpZmVsc2UoYmluU2l6ZSA9PSA1MDAwLCBzdGFydDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiaW5TaXplID09IDEwMDAwLCBzdGFydDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydDEgKyAxMDAwMCkpLAogICAgICAgICAgICAgICAgYWRqX2VuZDEgPSBhZGpfc3RhcnQxICsgNTAwMCwKICAgICAgICAgICAgICAgIGFkal9zdGFydDIgPSBpZmVsc2UoYmluU2l6ZSA9PSA1MDAwLCBzdGFydDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiaW5TaXplID09IDEwMDAwLCBzdGFydDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydDIgKyAxMDAwMCkpLAogICAgICAgICAgICAgICAgYWRqX2VuZDIgPSBhZGpfc3RhcnQyICsgNTAwMCwKICAgICAgICAgICAgICAgIGFuY2hvcjEgPSBwYXN0ZShjaHJvbTEsIGFkal9zdGFydDEsIGFkal9lbmQxLCBzZXAgPSAiXyIpLAogICAgICAgICAgICAgICAgYW5jaG9yMiA9IHBhc3RlKGNocm9tMiwgYWRqX3N0YXJ0MiwgYWRqX2VuZDIsIHNlcCA9ICJfIikpCgojIGRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2LCAxMSwgMTIsIDEzLCAyMiwgMjMsIDI0LCAyNSwgMjcpKSAlPiUgCiMgICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBlbmQxIC0gc3RhcnQxLAojICAgICAgICAgICAgICAgICBhZGpfc3RhcnQxID0gaWZlbHNlKGJpblNpemUgPT0gNTAwMCwgc3RhcnQxLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiaW5TaXplID09IDEwMDAwLCBzdGFydDErNTAwMCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQxICsgMTAwMDApKSwKIyAgICAgICAgICAgICAgICAgYWRqX2VuZDEgPSBhZGpfc3RhcnQxICsgNTAwMCwKIyAgICAgICAgICAgICAgICAgYWRqX3N0YXJ0MiA9IGlmZWxzZShiaW5TaXplID09IDUwMDAsIHN0YXJ0MiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYmluU2l6ZSA9PSAxMDAwMCwgc3RhcnQyICsgNTAwMCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQyICsgMTAwMDApKSwKIyAgICAgICAgICAgICAgICAgYWRqX2VuZDIgPSBhZGpfc3RhcnQyICsgNTAwMCwKIyAgICAgICAgICAgICAgICAgYW5jaG9yMSA9IHBhc3RlKGNocm9tMSwgYWRqX3N0YXJ0MSwgYWRqX2VuZDEsIHNlcCA9ICJfIiksCiMgICAgICAgICAgICAgICAgIGFuY2hvcjIgPSBwYXN0ZShjaHJvbTIsIGFkal9zdGFydDIsIGFkal9lbmQyLCBzZXAgPSAiXyIpKQoKZGF0YS5yZWcgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIsICJFLUUiLCAiRS1TIiwgIkUtWCIpKQoKIyMgR3JhcGgKI2luc3RhbGwucGFja2FnZXMoImlncmFwaCIpCmxpYnJhcnkoaWdyYXBoKQoKIyBUbyBiZSBhYmxlIHRvIGNvbnN0cnVjdCBhIGdyYXBoLCBlYWNoIGFuY2hvciBuZWVkIHRvIGhhdmUgc2FtZSByZXNvbHV0aW9uLgojIFNoaW5rIHRoZSBzaXplIHRvIDEwIGtiCiMgSWYgdGhlIGFuY2hvciBpcyAyNWtiLCBjaG9vc2UgdGhlIG1pZGRsZSA1a2IgYmluCiMgSWYgdGhlIGFuY2hvciBpcyAxMGtiLCBjaG9vc2UgdGhlIGxlZnQgNWtiIGJpbgoKZ3JhcGggPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRhdGEucmVnICU+JSBkcGx5cjo6c2VsZWN0KGFuY2hvcjEsIGFuY2hvcjIpKQpjb21wb25lbnRzIDwtIGNvbXBvbmVudHMoZ3JhcGgpCmRhdGEucmVnJGh1YiA8LSBjb21wb25lbnRzJG1lbWJlcnNoaXBbZGF0YS5yZWckYW5jaG9yMV0KCnRlbXAuYmVkcGUgPC0gZGF0YS5yZWcgJT4lIGRwbHlyOjpzZWxlY3QoY2hyb20xLCBhZGpfc3RhcnQxLCBhZGpfZW5kMSwgY2hyb20yLCBhZGpfc3RhcnQyLCBhZGpfZW5kMikKZndyaXRlKHRlbXAuYmVkcGUsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9yZWd1bGF0b3J5XzVrYkFkai5iZWRwZSIpKSwgCiAgICAgICBjb2wubmFtZXMgPSBGQUxTRSxyb3cubmFtZXMgPSBGQUxTRSwgc2VwID0gIlx0IikgIAoKaHViTnVtIDwtIGRhdGEucmVnICU+JSBncm91cF9ieShodWIpICU+JSBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgojIEh1YiBzaXplIGRpc3RyaWJ1dGlvbgpwIDwtIGdncGxvdChodWJOdW0sIGFlcyh4ID0gY291bnQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoICA9IDEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfeV9sb2cxMCgpCgpzdmdsaXRlKGhlcmUoZmlnRGlyLCAiaHViX3NpemVfZGlzdHJpYnV0aW9uLnN2ZyIpLCBoZWlnaHQgPSAyLCB3aWR0aCA9IDIpCnByaW50KHApCmRldi5vZmYoKQoKZGF0YS5yZWcgPC0gZGF0YS5yZWcgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oaHViTnVtLCBieSA9ICJodWIiKSAKZGF0YS5yZWcgPC0gZGF0YS5yZWcgJT4lIGRwbHlyOjptdXRhdGUocGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCiMgRXhwb3J0aW5nIHJlZ3VsYXRvcnkgbG9vcHMgd2l0aCBzcGVjaWZpYyBodWIgc2l6ZQp0ZW1wLmJlZHBlIDwtIGRhdGEucmVnICU+JSBkcGx5cjo6ZmlsdGVyKGNvdW50ID49IDMpICU+JSBkcGx5cjo6c2VsZWN0KGNocm9tMSwgYWRqX3N0YXJ0MSwgYWRqX2VuZDEsIGNocm9tMiwgYWRqX3N0YXJ0MiwgYWRqX2VuZDIpCmZ3cml0ZSh0ZW1wLmJlZHBlLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcmVndWxhdG9yeV81a2JBZGpfaHViMy5iZWRwZSIpKSwgCiAgICAgICBjb2wubmFtZXMgPSBGQUxTRSxyb3cubmFtZXMgPSBGQUxTRSwgc2VwID0gIlx0IikgIAoKdGVtcC5iZWRwZSA8LSBkYXRhLnJlZyAlPiUgZHBseXI6OmZpbHRlcihjb3VudCA+PSA1KSAlPiUgZHBseXI6OnNlbGVjdChjaHJvbTEsIGFkal9zdGFydDEsIGFkal9lbmQxLCBjaHJvbTIsIGFkal9zdGFydDIsIGFkal9lbmQyKQpmd3JpdGUodGVtcC5iZWRwZSwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3JlZ3VsYXRvcnlfNWtiQWRqX2h1YjUuYmVkcGUiKSksIAogICAgICAgY29sLm5hbWVzID0gRkFMU0Uscm93Lm5hbWVzID0gRkFMU0UsIHNlcCA9ICJcdCIpCgp0ZW1wLmJlZHBlIDwtIGRhdGEucmVnICU+JSBkcGx5cjo6ZmlsdGVyKGNvdW50ID49IDEwKSAlPiUgZHBseXI6OnNlbGVjdChjaHJvbTEsIGFkal9zdGFydDEsIGFkal9lbmQxLCBjaHJvbTIsIGFkal9zdGFydDIsIGFkal9lbmQyKQpmd3JpdGUodGVtcC5iZWRwZSwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3JlZ3VsYXRvcnlfNWtiQWRqX2h1YjEwLmJlZHBlIikpLCAKICAgICAgIGNvbC5uYW1lcyA9IEZBTFNFLHJvdy5uYW1lcyA9IEZBTFNFLCBzZXAgPSAiXHQiKQoKCiMgQWRkaW5nIGdlbmUgYW5ub3RhdGlvbiB0byBodWJzCmdlbmVQZWFrUGFpciA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjptdXRhdGUocGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lIGRwbHlyOjpzZWxlY3QocGVha0lELCBnZW5lKQpkYXRhLnJlZyA8LSBkYXRhLnJlZyAlPiUgZHBseXI6OmxlZnRfam9pbihnZW5lUGVha1BhaXIsIGJ5ID0gInBlYWtJRCIpCgojIER1cmluZyB1bm5lc3RpbmcsIEUtTiBsb29wcyB3aXRob3V0IGdlbmUgYW5ub3RhdGVkIGFyZSByZW1vdmVkCmRhdGEucmVnIDwtIGRhdGEucmVnICU+JSB1bm5lc3QoZ2VuZSkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXAyLCAiZ3JvdXAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwMywgImdyb3VwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA0LCAiZ3JvdXA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA1LCAiZ3JvdXA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwNiwgImdyb3VwNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA3LCAiZ3JvdXA3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmUuZ3JvdXA4LCAiZ3JvdXA4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBnZW5lLmdyb3VwOSwgImdyb3VwOSIsIE5BKSkpKSkpKSkpCikKCgp0ZW1wIDwtIGRhdGEucmVnICU+JSBkcGx5cjo6c2VsZWN0KGdlbmUsIGh1YiwgY291bnQsIGdyb3VwKSAlPiUKICBncm91cF9ieShnZW5lKSAlPiUgc2xpY2VfbWF4KGNvdW50LCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OmZpbHRlcihncm91cCAlaW4lIGMoImdyb3VwMSIsICJncm91cDIiLCAiZ3JvdXA1IiwgImdyb3VwOCIpKQoKCiMgVEVNUCBTVEFSVAojIFRFTVAgU1RBUlQKZ2VuZUxpc3QuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMS50c3YiKSkKZ2VuZUxpc3QuZ3JvdXAxLnRlbXAgPC0gZ2VuZUxpc3QuZ3JvdXAxICU+JSBkcGx5cjo6bGVmdF9qb2luKHRlbXAsIGJ5ID0gYygiZ2VuZSIpKQojIFRFTVAgRU5ECgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkY291bnQKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkY291bnQKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKcHYxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDIiKSwgNSkKcHYxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDUiKSwgNSkKcHYxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMSIsICJncm91cDgiKSwgNSkKcHYyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMiIsICJncm91cDUiKSwgNSkKcHYyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwMiIsICJncm91cDgiKSwgNSkKcHY1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXBTdW0sImdyb3VwNSIsICJncm91cDgiKSwgNSkKCgpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGdyb3VwLCB5ID0gY291bnQsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDMwLCBieSA9IDUpLCBsaW1pdHMgPSBjKDAsIDMwKSkgKyAKCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMywgbGFiZWwgPSBwYXN0ZTAoInB2MTI6ICIsIHB2MTIsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjE1OiAiLCBwdjE1LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHYxODogIiwgcHYxOCwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2MjU6ICIsIHB2MjUsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdjI4OiAiLCBwdjI4LCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHY1ODogIiwgcHY1OCwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMSkgKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiY291bnRIdWJfYmFycGxvdF9kaWZmR3JvdXBfZFRBR192c19ETVNPIikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCgpgYGAKCgojIyBbMi4xNF0gTG9va2luZyBkZWVwZXIgaW50byBUQUQgYW5kIGluc3VsYXRpb24KIyMjIEluc3VsYXRpb24gc2NvcmUgb2YgVFNTPwojIyMjIEltcG9ydGluZyBpbnN1bGF0aW9uIHNjb3JlCmBgYHtyfQojIEltcG9ydCBpbnN1bGF0aW9uIHNjb3JlIGNhbGN1bGF0ZWQgd2l0aCBweXRob24KcmVzdWx0RGlyIDwtIGhlcmUoIi4uLy4uL3Jlc3VsdCIpCmluc1Njb3JlLkRNU08gPC0gZnJlYWQoaGVyZShyZXN1bHREaXIsICJUQUQiLCAiaW5zdWxhdGlvblNjb3JlXzI1a2JfRzFETVNPLnRzdiIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAibG9nMl9pbnN1bGF0aW9uX3Njb3JlXzEyNTAwMCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGJpbklEID0gcGFzdGUoY2hyb20sIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIikpCmNvbG5hbWVzKGluc1Njb3JlLkRNU08pIDwtIGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJpbnN1bGF0aW9uU2NvcmUiLCAiYmluSUQiKQppbnNTY29yZS5kVEFHIDwtIGZyZWFkKGhlcmUocmVzdWx0RGlyLCAiVEFEIiwgImluc3VsYXRpb25TY29yZV8yNWtiX0cxZFRBRy50c3YiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImxvZzJfaW5zdWxhdGlvbl9zY29yZV8xMjUwMDAiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShiaW5JRCA9IHBhc3RlKGNocm9tLCBzdGFydCwgZW5kLCBzZXAgPSAiXyIpKQpjb2xuYW1lcyhpbnNTY29yZS5kVEFHKSA8LSBjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAiaW5zdWxhdGlvblNjb3JlIiwgImJpbklEIikKCiNpbnNTY29yZSA8LSBmdWxsX2pvaW4oaW5zU2NvcmUuRE1TTywgaW5zU2NvcmUuZFRBRywgYnkgPSBjKCJiaW5JRCIpKSAlPiUKIyAgZHBseXI6OnNlbGVjdChiaW5JRCwgY2hyb20ueCwgc3RhcnQueCwgZW5kLngsIGluc3VsYXRpb25TY29yZS54LCBpbnN1bGF0aW9uU2NvcmUueSkgCgojY29sbmFtZXMoaW5zU2NvcmUpIDwtIGMoImJpbklEIiwgImNociIsICJzdGFydCIsICJlbmQiLCAiaW5zdWxhdGlvbl9zY29yZV9ETVNPIiwgImluc3VsYXRpb25fc2NvYXJlX2RUQUciKQoKI1ZpZXcoaW5zU2NvcmUpCgpgYGAKCiMjIyMgTGlua2luZyB0byBnZW5lCmBgYHtyfQpnZW5lLlRTUy50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMykpICU+JQogIGRwbHlyOjpzZWxlY3QoVjYsIFY1LCBWMSwgVFNTKQpjb2xuYW1lcyhnZW5lLlRTUy50YikgPC0gYygiZW5zZW1ibCIsICJnZW5lIiwgImNociIsICJUU1MiKQoKZ2V0SW5zdWxhdGlvblNjb3JlIDwtIGZ1bmN0aW9uKGNociwgVFNTLCBpbnNTY29yZS50Yil7CiAgdGVtcC50YiA8LSBpbnNTY29yZS50YiAlPiUgZHBseXI6OmZpbHRlcihjaHJvbSA9PSBjaHIsIHN0YXJ0IDwgVFNTLCBlbmQgPiBUU1MpCiAgb3V0IDwtIHRlbXAudGIkaW5zdWxhdGlvblNjb3JlCiAgaWYobGVuZ3RoKG91dCkgPCAxKXsKICAgIHJldHVybihOQSkKICB9ZWxzZXsKICAgIHJldHVybih0ZW1wLnRiJGluc3VsYXRpb25TY29yZSkKICB9Cn0KCmdlbmUuaW5zU2NvcmUuYWxsIDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoCiAgbG9nMl9pbnNTY29yZV9ETVNPID0gZ2V0SW5zdWxhdGlvblNjb3JlKGNociwgVFNTLCBpbnNTY29yZS5ETVNPKSwKICBpbnNTY29yZV9ETVNPID0gMl5sb2cyX2luc1Njb3JlX0RNU08sCiAgbG9nMl9pbnNTY29yZV9kVEFHID0gZ2V0SW5zdWxhdGlvblNjb3JlKGNociwgVFNTLCBpbnNTY29yZS5kVEFHKSwKICBpbnNTY29yZV9kVEFHID0gMl5sb2cyX2luc1Njb3JlX2RUQUcsCiAgZGlmZl9pbnNTY29yZSA9IGluc1Njb3JlX2RUQUcgLSBpbnNTY29yZV9ETVNPKQoKCmBgYAoKIyMjIyBDaGVja2luZyBpbnN1bGF0aW9uIHNjb3JlIG9mIHRoZSBuZWFyZXN0IFRBRApgYGB7cn0KIyBJbXBvcnRpbmcgVEFEIGJvdW5kYXJpZXMKdGFkX2JvdW5kYXJ5IDwtIGZyZWFkKGhlcmUoIi4uLy4uL3Jlc3VsdC9UQUQiLCAiVEFEXzI1a2JfMTI1a2Jfb3RzdV9ib3VuZGFyaWVzX0cxRE1TTy5iZWQiKSkKY29sbmFtZXModGFkX2JvdW5kYXJ5KSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgZHBseXI6Om11dGF0ZSh0YWRfaWQgPSBwYXN0ZShjaHIsIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yKQoKZmluZENsb3Nlc3RUQURCb3VuZGFyeSA8LSBmdW5jdGlvbihjaHJvbSwgVFNTLCB0YWRfYm91bmRhcnkpewogIHRlbXAgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6ZmlsdGVyKGNociA9PSBjaHJvbSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gYWJzKGNlbnRlciAtIFRTUykpICU+JQogICAgc2xpY2VfbWluKGRpc3RhbmNlKQogIGlmKG5yb3codGVtcCkgPT0gMSl7CiAgICAgIHJldHVybih0ZW1wJGNlbnRlcikKICB9ZWxzZXsKICAgIHJldHVybihOQSkKICB9Cn0KCgpnZW5lLmluc1Njb3JlLmFsbCA8LSBnZW5lLmluc1Njb3JlLmFsbCAlPiUgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUoY2xvc2VzdEJvdW5kYXJ5ID0gZmluZENsb3Nlc3RUQURCb3VuZGFyeShjaHIsIFRTUywgdGFkX2JvdW5kYXJ5KSwKICAgICAgICAgICAgICAgIGxvZzJfYm91bmRhcnlJbnNTY29yZV9ETVNPID0gZ2V0SW5zdWxhdGlvblNjb3JlKGNociwgY2xvc2VzdEJvdW5kYXJ5LCBpbnNTY29yZS5ETVNPKSwKICAgICAgICAgICAgICAgIGJvdW5kYXJ5SW5zU2NvcmVfRE1TTyA9IDJebG9nMl9ib3VuZGFyeUluc1Njb3JlX0RNU08sCiAgICAgICAgICAgICAgICBsb2cyX2JvdW5kYXJ5SW5zU2NvcmVfZFRBRyA9IGdldEluc3VsYXRpb25TY29yZShjaHIsIGNsb3Nlc3RCb3VuZGFyeSwgaW5zU2NvcmUuZFRBRyksCiAgICAgICAgICAgICAgICBib3VuZGFyeUluc1Njb3JlX2RUQUcgPSAyXmxvZzJfYm91bmRhcnlJbnNTY29yZV9kVEFHLAogICAgICAgICAgICAgICAgZGlmZl9ib3VuZGFyeUluc1Njb3JlID0gYm91bmRhcnlJbnNTY29yZV9kVEFHIC0gYm91bmRhcnlJbnNTY29yZV9ETVNPKQoKc2F2ZVJEUyhnZW5lLmluc1Njb3JlLmFsbCwgaGVyZShyZXN1bHREaXIsICJnZW5lLmluc1Njb3JlLmFsbC5yZHMiKSkKZ2VuZS5pbnNTY29yZS5hbGwgPC0gcmVhZFJEUyhoZXJlKHJlc3VsdERpciwgImdlbmUuaW5zU2NvcmUuYWxsLnJkcyIpKQpgYGAKIyMjIyMgUGxvdHRpbmcgZm9yIGJpbmFyeSBncm91cHMKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKCmdlbmUuaW5zU2NvcmUgPC0gZ2VuZS5pbnNTY29yZS5hbGwgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMiwgImdyb3VwMiIsIE5BKSkpICU+JSAKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgoKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJHNjb3JlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJHNjb3JlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfaW5zU2NvcmUgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IC0xLjUsIHltYXggPSAwKXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gIi4iLCBmaWxsID0gZ3JvdXAsIHkgPSAtc2NvcmUpKSArIAogICAgbGFicyh4ID0gTlVMTCwgeSA9ICItIEluc3VsYXRpb24gc2NvcmUiKSArICAjIFJlbW92ZSB4LWF4aXMgdGl0bGUKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHJldigoYygiIzc3Nzc3NyIsICIjRjI4RTJDIikpKSkgKwoKICAgIGludHJvZGF0YXZpejo6Z2VvbV9zcGxpdF92aW9saW4obGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC40KSArCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BLCAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gRkFMU0UpICsgdGhlbWVfY2xhc3NpYygpICsKICAgIHN0YXRfc3VtbWFyeSgKICAgICAgYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLAogICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICAgICkgKwogICAgCiAgICAjIAogICAgIyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgY29sb3IgPSAiYmxhY2siLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICAjIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgIGNvbG9yID0gImJsYWNrIiwgbGluZXdpZHRoID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgIyAgICAgICAgICAgICAgb3V0bGllci5zaXplID0gMSwgb3V0bGllci5zdHJva2UgPSBOQSkgKwogICAgIyBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDEsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKHltaW4sIHltYXgpKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0geW1pbiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICAgIHRoZW1lKAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKSsgICBndWlkZXMoCiAgICAgIGZpbGwgPSBndWlkZV9sZWdlbmQoCiAgICAgICAga2V5d2lkdGggPSAwLjIsICAjIEFkanVzdCB0aGUgd2lkdGggb2YgdGhlIGxlZ2VuZCBrZXlzCiAgICAgICAga2V5aGVpZ2h0ID0gMC4yICAjIEFkanVzdCB0aGUgaGVpZ2h0IG9mIHRoZSBsZWdlbmQga2V5cwogICAgICApKQogICAgICAKICAgICAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uX3Njb3JlX2JpbmFyeUdyb3VwXyIsIG5vdGUpCiAgd2lkdGggPC0gcGFuZWxTaXplKDEuNTUpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS4yKSptbVRvSW5jaAogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CgojIERNU08KdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBib3VuZGFyeUluc1Njb3JlX0RNU08pCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X0RNU09fYmluYXJ5R3JvdXAiLCB5bWluID0gLTEuMSwgeW1heCA9IC0wLjUpCgojIGRUQUcKdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBib3VuZGFyeUluc1Njb3JlX2RUQUcpCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X2RUQUdfYmluYXJ5R3JvdXAiLCB5bWluID0gIC0xLjEsIHltYXggPSAtMC41KQoKIyBkaWZmCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgZGlmZl9ib3VuZGFyeUluc1Njb3JlKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9kaWZmX2JpbmFyeUdyb3VwIiwgeW1pbiA9IC0wLjMsIHltYXggPSAwLjEpCmBgYAoKIyMjIyMgUGxvdHRpbmcgZm9yIGdyb3VwcwpgYGB7cn0KZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAyLnRzdiIpKSRnZW5lCmdyb3VwNSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDUudHN2IikpJGdlbmUKZ3JvdXA4IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwOC50c3YiKSkkZ2VuZQoKCmdlbmUuaW5zU2NvcmUgPC0gZ2VuZS5pbnNTY29yZS5hbGwgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMiwgImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXA1LCAiZ3JvdXA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXA4LCAiZ3JvdXA4IiwgTkEpKSkpKSAlPiUgCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRzY29yZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRzY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X2luc1Njb3JlIDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMS41KXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIHAxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiAgcDE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDgiKSwgNSkKICBwMjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQogIHAyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiAgcDU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwNSIsICJncm91cDgiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYyh5bWluLCB5bWF4KSkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IHltaW4gKyAxLCBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTU6ICIsIGNvbnZQdmFsdWUocDE1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxODogIiwgY29udlB2YWx1ZShwMTgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI1OiAiLCBjb252UHZhbHVlKHAyNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjg6ICIsIGNvbnZQdmFsdWUocDI4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInA1ODogIixjb252UHZhbHVlKCBwNTgpLCAiXG4iKSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImluc3VsYXRpb25fc2NvcmVfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQoKIyBETVNPCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgYm91bmRhcnlJbnNTY29yZV9ETVNPKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9ETVNPIikKCiMgZFRBRwp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGJvdW5kYXJ5SW5zU2NvcmVfZFRBRykKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfZFRBRyIpCgojIGRpZmYKdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBkaWZmX2JvdW5kYXJ5SW5zU2NvcmUpCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X2RpZmYiLCB5bWluID0gLTAuNSwgeW1heCA9IDEpCmBgYAoKIyMjIyMgUGxvdHRpbmcgZm9yIFAtTgpgYGB7cn0KdGVtcDIgPC0gcmVhZFJEUyhoZXJlKHJlc3VsdERpciwgImdlbmVfbG9vcF9saW5rLnJkcyIpKQoKcG5PdmVyOCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gOCkpJGdlbmUKcG5PdmVyNiA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gNiwgdG90YWwgPCA4KSkkZ2VuZQpwbk92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcih0b3RhbCA+PSA0LCB0b3RhbCA8IDYpKSRnZW5lCnBuT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDIsIHRvdGFsIDwgNCkpJGdlbmUKcG5PdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPCAyKSkkZ2VuZQoKCmdlbmUuaW5zU2NvcmUgPC0gZ2VuZS5pbnNTY29yZS5hbGwgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgcG5PdmVyOCwgInA4IiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIHBuT3ZlcjYsICJwNiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcG5PdmVyNCwgInA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcG5PdmVyMiwgInAyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBwbk92ZXIwLCAicDAiLCBOQSkpKSkpKSAgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRzY29yZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRzY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnBsb3RfaW5zU2NvcmUgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAxLjUpewogIHAwMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMCIsICJwMiIpLCA1KQogIHAyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMiIsICJwNCIpLCA1KQogIHA0NiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwNCIsICJwNiIpLCA1KQogIHA2OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwNiIsICJwOCIpLCA1KQogIHA0OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwNCIsICJwOCIpLCA1KQogIHAyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMiIsICJwOCIpLCA1KQogIHAwOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMCIsICJwOCIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gZ3JvdXAsIHkgPSBzY29yZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBncm91cCksIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKHltaW4sIHltYXgpKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0geW1pbiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMDI6ICIsIGNvbnZQdmFsdWUocDAyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNDogIiwgY29udlB2YWx1ZShwMjQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDQ2OiAiLCBjb252UHZhbHVlKHA0NiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwNjg6ICIsIGNvbnZQdmFsdWUocDY4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInA0ODogIiwgY29udlB2YWx1ZShwNDgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLGNvbnZQdmFsdWUoIHAyOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMDg6ICIsY29udlB2YWx1ZSggcDA4KSwgIlxuIiksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjZDlkOWQ5IiwgIiNiZGJkYmQiLCAiIzk2OTY5NiIsICIjNzM3MzczIiwgIiM1MjUyNTIiKSkKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImluc3VsYXRpb25fc2NvcmVfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQoKIyBETVNPCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgYm91bmRhcnlJbnNTY29yZV9ETVNPKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9ETVNPX1AtTiIpCgojIGRUQUcKdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBib3VuZGFyeUluc1Njb3JlX2RUQUcpCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X2RUQUdfUC1OIikKCiMgZGlmZgp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGRpZmZfYm91bmRhcnlJbnNTY29yZSkKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfZGlmZl9QLU4iLCB5bWluID0gLTAuNSwgeW1heCA9IDEpCgpgYGAKIyMjIyMgUGxvdHRpbmcgZm9yIFAtUwpgYGB7cn0KdGVtcDIgPC0gcmVhZFJEUyhoZXJlKHJlc3VsdERpciwgImdlbmVfbG9vcF9saW5rLnJkcyIpKQoKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAzLCBudW1fcHMgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMiwgbnVtX3BzIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDEsIG51bV9wcyA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA8IDEpKSRnZW5lCgoKZ2VuZS5pbnNTY29yZSA8LSBnZW5lLmluc1Njb3JlLmFsbCAlPiUgcm93d2lzZSgpICU+JSBkcGx5cjo6bXV0YXRlKAogIGdyb3VwID0gaWZlbHNlKGVuc2VtYmwgJWluJSBwc092ZXI0LCAicDQiLAogICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcHNPdmVyMywgInAzIiwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBwc092ZXIyLCAicDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBwc092ZXIxLCAicDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIHBzT3ZlcjAsICJwMCIsIE5BKSkpKSkpICAlPiUgCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJHNjb3JlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJHNjb3JlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKcGxvdF9pbnNTY29yZSA8LSBmdW5jdGlvbih0ZW1wLnRiLCBub3RlLCB5bWluID0gMCwgeW1heCA9IDEuNSl7CiAgcDAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAwIiwgInAxIiksIDUpCiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAxIiwgInAyIiksIDUpCiAgcDIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAyIiwgInAzIiksIDUpCiAgcDM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAzIiwgInA0IiksIDUpCiAgcDI0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAyIiwgInA0IiksIDUpCiAgcDE0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAxIiwgInA0IiksIDUpCiAgcDA0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgInAwIiwgInA0IiksIDUpCiAgCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSBncm91cCwgeSA9IHNjb3JlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoeW1pbiwgeW1heCkpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSB5bWluICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAwMTogIiwgY29udlB2YWx1ZShwMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDEyOiAiLCBjb252UHZhbHVlKHAxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjM6ICIsIGNvbnZQdmFsdWUocDIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAzNDogIiwgY29udlB2YWx1ZShwMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI0OiAiLCBjb252UHZhbHVlKHAyNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTQ6ICIsY29udlB2YWx1ZSggcDE0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAwNDogIixjb252UHZhbHVlKCBwMDQpLCAiXG4iKSwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNkOWQ5ZDkiLCAiI2JkYmRiZCIsICIjOTY5Njk2IiwgIiM3MzczNzMiLCAiIzUyNTI1MiIpKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiaW5zdWxhdGlvbl9zY29yZV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMwogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CgojIERNU08KdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBib3VuZGFyeUluc1Njb3JlX0RNU08pCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X0RNU09fUC1TIikKCiMgZFRBRwp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGJvdW5kYXJ5SW5zU2NvcmVfZFRBRykKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfZFRBR19QLVMiKQoKIyBkaWZmCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgZGlmZl9ib3VuZGFyeUluc1Njb3JlKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9kaWZmX1AtUyIsIHltaW4gPSAtMC41LCB5bWF4ID0gMSkKYGBgCiMjIyMjIFBsb3R0aW5nIGZvciBQLUUKYGBge3J9CnRlbXAyIDwtIHJlYWRSRFMoaGVyZShyZXN1bHREaXIsICJnZW5lX2xvb3BfbGluay5yZHMiKSkKCnBlT3ZlcjQgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSA0KSkkZ2VuZQpwZU92ZXIzIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMywgbnVtX3BlIDwgNCkpJGdlbmUKcGVPdmVyMiA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDIsIG51bV9wZSA8IDMpKSRnZW5lCnBlT3ZlcjEgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAxLCBudW1fcGUgPCAyKSkkZ2VuZQpwZU92ZXIwIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPCAxKSkkZ2VuZQoKCmdlbmUuaW5zU2NvcmUgPC0gZ2VuZS5pbnNTY29yZS5hbGwgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgcGVPdmVyNCwgInA0IiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIHBlT3ZlcjMsICJwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcGVPdmVyMiwgInAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcGVPdmVyMSwgInAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBwZU92ZXIwLCAicDAiLCBOQSkpKSkpKSAgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRzY29yZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRzY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnBsb3RfaW5zU2NvcmUgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAxLjUpewogIHAwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMCIsICJwMSIpLCA1KQogIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMSIsICJwMiIpLCA1KQogIHAyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMiIsICJwMyIpLCA1KQogIHAzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMyIsICJwNCIpLCA1KQogIHAyNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMiIsICJwNCIpLCA1KQogIHAxNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMSIsICJwNCIpLCA1KQogIHAwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJwMCIsICJwNCIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gZ3JvdXAsIHkgPSBzY29yZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBncm91cCksIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKHltaW4sIHltYXgpKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0geW1pbiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMDE6ICIsIGNvbnZQdmFsdWUocDAxKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxMjogIiwgY29udlB2YWx1ZShwMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDIzOiAiLCBjb252UHZhbHVlKHAyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMzQ6ICIsIGNvbnZQdmFsdWUocDM0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNDogIiwgY29udlB2YWx1ZShwMjQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE0OiAiLGNvbnZQdmFsdWUoIHAxNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMDQ6ICIsY29udlB2YWx1ZSggcDA0KSwgIlxuIiksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjZDlkOWQ5IiwgIiNiZGJkYmQiLCAiIzk2OTY5NiIsICIjNzM3MzczIiwgIiM1MjUyNTIiKSkKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImluc3VsYXRpb25fc2NvcmVfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQoKIyBETVNPCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgYm91bmRhcnlJbnNTY29yZV9ETVNPKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9ETVNPX1AtRSIpCgojIGRUQUcKdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBib3VuZGFyeUluc1Njb3JlX2RUQUcpCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X2RUQUdfUC1FIikKCiMgZGlmZgp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGRpZmZfYm91bmRhcnlJbnNTY29yZSkKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfZGlmZl9QLUUiLCB5bWluID0gLTAuNSwgeW1heCA9IDEpCmBgYAojIyMjIyBQbG90dGluZyBmb3IgUC1QCmBgYHtyfQp0ZW1wMiA8LSByZWFkUkRTKGhlcmUocmVzdWx0RGlyLCAiZ2VuZV9sb29wX2xpbmsucmRzIikpCgpwcE92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gNCkpJGdlbmUKcHBPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDMsIG51bV9wcCA8IDQpKSRnZW5lCnBwT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAyLCBudW1fcHAgPCAzKSkkZ2VuZQpwcE92ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMSwgbnVtX3BwIDwgMikpJGdlbmUKcHBPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwIDwgMSkpJGdlbmUKCgpnZW5lLmluc1Njb3JlIDwtIGdlbmUuaW5zU2NvcmUuYWxsICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZW5zZW1ibCAlaW4lIHBwT3ZlcjQsICJwNCIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBwcE92ZXIzLCAicDMiLAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIHBwT3ZlcjIsICJwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIHBwT3ZlcjEsICJwMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgcHBPdmVyMCwgInAwIiwgTkEpKSkpKSkgICU+JSAKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkc2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkc2NvcmUKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgpwbG90X2luc1Njb3JlIDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMS41KXsKICBwMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDAiLCAicDEiKSwgNSkKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDEiLCAicDIiKSwgNSkKICBwMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDIiLCAicDMiKSwgNSkKICBwMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDMiLCAicDQiKSwgNSkKICBwMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDIiLCAicDQiKSwgNSkKICBwMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDEiLCAicDQiKSwgNSkKICBwMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAicDAiLCAicDQiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gc2NvcmUpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYyh5bWluLCB5bWF4KSkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IHltaW4gKyAxLCBsYWJlbCA9IHBhc3RlMCgicDAxOiAiLCBjb252UHZhbHVlKHAwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyMzogIiwgY29udlB2YWx1ZShwMjMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDM0OiAiLCBjb252UHZhbHVlKHAzNCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjQ6ICIsIGNvbnZQdmFsdWUocDI0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNDogIixjb252UHZhbHVlKCBwMTQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDA0OiAiLGNvbnZQdmFsdWUoIHAwNCksICJcbiIpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2Q5ZDlkOSIsICIjYmRiZGJkIiwgIiM5Njk2OTYiLCAiIzczNzM3MyIsICIjNTI1MjUyIikpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uX3Njb3JlXyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAzCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCiMgRE1TTwp0ZW1wLnRiIDwtIGdlbmUuaW5zU2NvcmUgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGJvdW5kYXJ5SW5zU2NvcmVfRE1TTykKY29sbmFtZXModGVtcC50YikgPC0gYygiZ3JvdXAiLCAic2NvcmUiKQpwbG90X2luc1Njb3JlKHRlbXAudGIsICJuZWFyZXN0Qm91bmRhcnlfRE1TT19QLVAiKQoKIyBkVEFHCnRlbXAudGIgPC0gZ2VuZS5pbnNTY29yZSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgYm91bmRhcnlJbnNTY29yZV9kVEFHKQpjb2xuYW1lcyh0ZW1wLnRiKSA8LSBjKCJncm91cCIsICJzY29yZSIpCnBsb3RfaW5zU2NvcmUodGVtcC50YiwgIm5lYXJlc3RCb3VuZGFyeV9kVEFHX1AtUCIpCgojIGRpZmYKdGVtcC50YiA8LSBnZW5lLmluc1Njb3JlICU+JSBkcGx5cjo6c2VsZWN0KGdyb3VwLCBkaWZmX2JvdW5kYXJ5SW5zU2NvcmUpCmNvbG5hbWVzKHRlbXAudGIpIDwtIGMoImdyb3VwIiwgInNjb3JlIikKcGxvdF9pbnNTY29yZSh0ZW1wLnRiLCAibmVhcmVzdEJvdW5kYXJ5X2RpZmZfUC1QIiwgeW1pbiA9IC0wLjUsIHltYXggPSAxKQpgYGAKCgojIyBbMi4xNV0gVEFEIGRpc3RhbmNlL3NpemUKIyMjIyBMaW5rIFRBRApgYGB7cn0KcmVmRGlyIDwtIGhlcmUoIi4uLy4uIiwgInJlZmVyZW5jZSIpCgojIEltcG9ydGluZyBUQUQgYm91bmRhcnkKdGFkX2JvdW5kYXJ5IDwtIGZyZWFkKGhlcmUoIi4uLy4uL3Jlc3VsdC9UQUQiLCAiVEFEXzI1a2JfMTI1a2Jfb3RzdV9ib3VuZGFyaWVzX0cxRE1TTy5iZWQiKSkKY29sbmFtZXModGFkX2JvdW5kYXJ5KSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgZHBseXI6Om11dGF0ZSh0YWRfaWQgPSBwYXN0ZShjaHIsIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yKQoKIyBJbXBvcnRpbmcgVEFECnRhZCA8LSBmcmVhZChoZXJlKCIuLi8uLi9yZXN1bHQvVEFEIiwgIlRBRF8yNWtiXzEyNWtiX290c3VfRzFETVNPLmJlZHBlIikpCmNvbG5hbWVzKHRhZCkgPC0gYygiY2hyMSIsICJzdGFydDEiLCAiZW5kMSIsICJjaHIyIiwgInN0YXJ0MiIsICJlbmQyIikKdGFkIDwtIHRhZCAlPiUgZHBseXI6Om11dGF0ZSh0YWRJRCA9IHBhc3RlKGNocjEsIHN0YXJ0MSwgZW5kMSwgc2VwID0gIl8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWRTaXplID0gZW5kMSAtIHN0YXJ0MSkKCiMgSW1wb3J0aW5nIGdlbmUKZ2VuZS5UU1MudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpKSAlPiUKICBkcGx5cjo6c2VsZWN0KFY2LCBWNSwgVjEsIFRTUykKY29sbmFtZXMoZ2VuZS5UU1MudGIpIDwtIGMoImVuc2VtYmwiLCAiZ2VuZSIsICJjaHIiLCAiVFNTIikKCiMgRnVuY3Rpb25zCmZpbmREaXN0YW5jZVRvVEFEIDwtIGZ1bmN0aW9uKGNocm9tLCBUU1MsIHRhZF9ib3VuZGFyeSl7CiAgdGVtcCA8LSB0YWRfYm91bmRhcnkgJT4lIGRwbHlyOjpmaWx0ZXIoY2hyID09IGNocm9tKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBhYnMoY2VudGVyIC0gVFNTKSkgJT4lIHNsaWNlX21pbihkaXN0YW5jZSkKICBpZihucm93KHRlbXApID09IDEpewogICAgcmV0dXJuKHRlbXAkZGlzdGFuY2UpCiAgfWVsc2V7CiAgICByZXR1cm4oTkEpCiAgfQp9CgpmaW5kSXRzVEFEIDwtIGZ1bmN0aW9uKGNocm9tLCBUU1MsIHRhZCl7CiAgdGVtcCA8LSB0YWQgJT4lIGRwbHlyOjpmaWx0ZXIoY2hyMSA9PSBjaHJvbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydDEgPCBUU1MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kMSA+IFRTUykKICBpZihucm93KHRlbXApID09IDEpewogICAgcmV0dXJuKHRlbXAkdGFkSUQpCiAgfWVsc2V7CiAgICByZXR1cm4oTkEpCiAgfQp9CgpmaW5kVEFEU2l6ZSA8LWZ1bmN0aW9uKGNocm9tLCBUU1MsIHRhZCl7CiAgdGVtcCA8LSB0YWQgJT4lIGRwbHlyOjpmaWx0ZXIoY2hyMSA9PSBjaHJvbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydDEgPCBUU1MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kMSA+IFRTUykKICBpZihucm93KHRlbXApID09IDEpewogICAgcmV0dXJuKHRlbXAkdGFkU2l6ZSkKICB9ZWxzZXsKICAgIHJldHVybihOQSkKICB9Cn0KCmdlbmUuVFNTLnRiIDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IGZpbmREaXN0YW5jZVRvVEFEKGNociwgVFNTLCB0YWRfYm91bmRhcnkpLAogICAgICAgICAgICAgICAgVEFEID0gZmluZEl0c1RBRChjaHIsIFRTUywgdGFkKSwKICAgICAgICAgICAgICAgIFRBRHNpemUgPSBmaW5kVEFEU2l6ZShjaHIsIFRTUywgdGFkKSkKYGBgCgojIyMjIyBkVEFHIC0gYmluYXJ5R3JvdXAKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKCmdlbmUuVFNTLnRiLnBsb3QgPC0gZ2VuZS5UU1MudGIgJT4lIHJvd3dpc2UoKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMiwgImdyb3VwMiIsIE5BKSkpICU+JSAKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgoKIyMgUGxvdCBkaXN0YW5jZQpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGRpc3RhbmNlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRkaXN0YW5jZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X1RBRGRpc3RhbmNlIDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9ICIuIiwgZmlsbCA9IGdyb3VwLCB5ID0gZGlzdGFuY2UpKSArCiAgICAjIFNldCBheGlzIGxhYmVscyAobm8geC1heGlzIHRpdGxlKQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gKChjKCIjNzc3Nzc3IiwgIiNGMjhFMkMiKSkpKSArCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gIkRpc3RhbmNlIGZyb20gVEFEIGJvdW5kYXJ5IikgKwogICAgIyBWaW9saW4gcGxvdCB3aXRoIGJsYWNrIG91dGxpbmUsIGN1c3RvbWl6ZWQgbGluZSB3aWR0aCBhbmQgZW5kCiAgICBpbnRyb2RhdGF2aXo6Omdlb21fc3BsaXRfdmlvbGluKAogICAgIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjQsCiAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSArCiAgICAjIEJveCBwbG90IHdpdGggY3VzdG9taXplZCBsaW5lIHdpZHRoLCBzcXVhcmUgZW5kLCBhbmQgb3V0bGllciBzaXplCiAgICBnZW9tX2JveHBsb3QoCiAgICAgIHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC42LAogICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgICApICsKICAgIAogICAgIyBNZWFuIHBvaW50IGluIGVhY2ggZ3JvdXAKICAgIHN0YXRfc3VtbWFyeSgKICAgICAgYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLAogICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICAgICkgKwogICAgCiAgICAjIEhvcml6b250YWwgbGluZSBhdCB5ID0gMAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgICAKICAgICMgQ29vcmRpbmF0ZSBsaW1pdHMgYW5kIGN1c3RvbSB5LWF4aXMgbGFiZWxzCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoeW1pbiwgeW1heCkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogICAgCiAgICAjIEFubm90YXRlIHAtdmFsdWUgdGV4dAogICAgYW5ub3RhdGUoCiAgICAgICJ0ZXh0IiwgeCA9IDEsIHkgPSB5bWluICsgMSwKICAgICAgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpKSwKICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzCiAgICApICsKICAgIAogICAgIyBUaGVtZSBjdXN0b21pemF0aW9uCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICAgICksCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICAgKSwKICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICAgICksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykpICsKICAgIGd1aWRlcygKICAgICAgZmlsbCA9IGd1aWRlX2xlZ2VuZCgKICAgICAgICBrZXl3aWR0aCA9IDAuMiwgICMgQWRqdXN0IHRoZSB3aWR0aCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICAgICBrZXloZWlnaHQgPSAwLjIgICMgQWRqdXN0IHRoZSBoZWlnaHQgb2YgdGhlIGxlZ2VuZCBrZXlzCiAgICAgICkKICAgICkKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImRpc3RhbmNlX3RvX2JvdW5kYXJ5XyIsIG5vdGUpCiAgd2lkdGggPC0gcGFuZWxTaXplKDEuNTUpKm1tVG9JbmNoCiAgaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCnBsb3RfVEFEZGlzdGFuY2UoZ2VuZS5UU1MudGIucGxvdCwgImdyb3VwX2JpbmF5R3JvdXAiLCB5bWF4ID0gMTAwMDAwMCkKCgojIyBQbG90IFRBRCBzaXplCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDEpICkkVEFEc2l6ZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDIpICkkVEFEc2l6ZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X1RBRHNpemUgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAyMDAwMDAwKXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gIi4iLCBmaWxsID0gZ3JvdXAsIHkgPSBUQURzaXplKSkgKwogICAgIyBTZXQgYXhpcyBsYWJlbHMgKG5vIHgtYXhpcyB0aXRsZSkKICAgIGxhYnMoeCA9IE5VTEwsIHkgPSAiU2l6ZSBvZiBUQUQiKSArCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gKChjKCIjNzc3Nzc3IiwgIiNGMjhFMkMiKSkpKSArCgogICAgIyBWaW9saW4gcGxvdCB3aXRoIGJsYWNrIG91dGxpbmUsIGN1c3RvbWl6ZWQgbGluZSB3aWR0aCBhbmQgZW5kCiAgICBpbnRyb2RhdGF2aXo6Omdlb21fc3BsaXRfdmlvbGluKAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0qIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLCBhbHBoYSA9IC40CiAgICApICsKICAgIAogICAgIyBCb3ggcGxvdCB3aXRoIGN1c3RvbWl6ZWQgbGluZSB3aWR0aCwgc3F1YXJlIGVuZCwgYW5kIG91dGxpZXIgc2l6ZQogICAgZ2VvbV9ib3hwbG90KAogICAgICB3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICBsaW5ld2lkdGggPSBsaW5lTWVkaXVtKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgb3V0bGllci5zaGFwZSA9IE5BLCAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gRkFMU0UKICAgICkgKwogICAgCiAgICAjIE1lYW4gcG9pbnQgaW4gZWFjaCBncm91cAogICAgc3RhdF9zdW1tYXJ5KAogICAgICBhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sCiAgICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgICBmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKC4zKQogICAgKSArCiAgICAKICAgICMgSG9yaXpvbnRhbCBsaW5lIGF0IHkgPSAwCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQpICsKICAgIAogICAgIyBDb29yZGluYXRlIGxpbWl0cyBhbmQgY3VzdG9tIHktYXhpcyBsYWJlbHMKICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYyh5bWluLCB5bWF4KSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKSArCiAgICAKICAgICMgQW5ub3RhdGUgcC12YWx1ZSB0ZXh0CiAgICBhbm5vdGF0ZSgKICAgICAgInRleHQiLCB4ID0gMSwgeSA9IHltaW4gKyAxLAogICAgICBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMikpLAogICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMKICAgICkgKwogICAgCiAgICAjIFRoZW1lIGN1c3RvbWl6YXRpb24KICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSArIGd1aWRlcygKICAgICAgZmlsbCA9IGd1aWRlX2xlZ2VuZCgKICAgICAgICBrZXl3aWR0aCA9IDAuMiwgICMgQWRqdXN0IHRoZSB3aWR0aCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICAgICBrZXloZWlnaHQgPSAwLjIgICMgQWRqdXN0IHRoZSBoZWlnaHQgb2YgdGhlIGxlZ2VuZCBrZXlzCiAgICAgICkpCiAgCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJzaXplX29mX2JvdW5kYXJ5XyIsIG5vdGUpCiAgd2lkdGggPC0gcGFuZWxTaXplKDEuNTUpKm1tVG9JbmNoCiAgaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KcGxvdF9UQURzaXplKGdlbmUuVFNTLnRiLnBsb3QsICJncm91cF9iaW5hcnlHcm91cCIsIHltYXggPSAzZTYpCmBgYAoKIyMjIyMgZFRBRyAtIFBsb3R0aW5nIGZvciBncm91cHMKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMi50c3YiKSkkZ2VuZQpncm91cDUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpKSRnZW5lCmdyb3VwOCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IikpJGdlbmUKCgpnZW5lLlRTUy50Yi5wbG90IDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDIsICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwNSwgImdyb3VwNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwOCwgImdyb3VwOCIsIE5BKSkpKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgojIyBQbG90IGRpc3RhbmNlCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDEpICkkZGlzdGFuY2UKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAyKSApJGRpc3RhbmNlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfVEFEZGlzdGFuY2UgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAyMDAwMDAwKXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIHAxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiAgcDE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDgiKSwgNSkKICBwMjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQogIHAyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiAgcDU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwNSIsICJncm91cDgiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlzdGFuY2UpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNTogIiwgY29udlB2YWx1ZShwMTUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE4OiAiLCBjb252UHZhbHVlKHAxOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyODogIiwgY29udlB2YWx1ZShwMjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDU4OiAiLGNvbnZQdmFsdWUoIHA1OCksICJcbiIpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZGlzdGFuY2VfdG9fYm91bmRhcnlfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQoKcGxvdF9UQURkaXN0YW5jZShnZW5lLlRTUy50Yi5wbG90LCAiZ3JvdXAiKQoKCiMjIFBsb3QgVEFEIHNpemUKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMSkgKSRUQURzaXplCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRUQURzaXplCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfVEFEc2l6ZSA8LSBmdW5jdGlvbih0ZW1wLnRiLCBub3RlLCB5bWluID0gMCwgeW1heCA9IDIwMDAwMDApewogIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXAyIiksIDUpCiAgcDE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDUiKSwgNSkKICBwMTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwOCIpLCA1KQogIHAyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA1IiksIDUpCiAgcDI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDgiKSwgNSkKICBwNTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXA1IiwgImdyb3VwOCIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gZ3JvdXAsIHkgPSBUQURzaXplKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAoeW1pbiArIHltYXgpLzIgKyAxLCBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTU6ICIsIGNvbnZQdmFsdWUocDE1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxODogIiwgY29udlB2YWx1ZShwMTgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI1OiAiLCBjb252UHZhbHVlKHAyNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjg6ICIsIGNvbnZQdmFsdWUocDI4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInA1ODogIixjb252UHZhbHVlKCBwNTgpLCAiXG4iKSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNpemVfb2ZfYm91bmRhcnlfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQpwbG90X1RBRHNpemUoZ2VuZS5UU1MudGIucGxvdCwgImdyb3VwIiwgeW1heCA9IDZlNikKYGBgCgojIyMjIyBBNDg1IC0gUGxvdHRpbmcgZm9yIGdyb3VwcwpgYGB7cn0KZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAyLnRzdiIpKSRnZW5lCmdyb3VwMyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDMudHN2IikpJGdlbmUKZ3JvdXA0IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwNC50c3YiKSkkZ2VuZQpncm91cDUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpKSRnZW5lCmdyb3VwNiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDYudHN2IikpJGdlbmUKZ3JvdXA3IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwNy50c3YiKSkkZ2VuZQpncm91cDggPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA4LnRzdiIpKSRnZW5lCmdyb3VwOSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDkudHN2IikpJGdlbmUKCgpnZW5lLlRTUy50Yi5wbG90IDwtIGdlbmUuVFNTLnRiICU+JQogIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgZ3JvdXAgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBlbnNlbWJsICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgICAgIGVuc2VtYmwgJWluJSBncm91cDIgfiAiZ3JvdXAyIiwKICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwMyB+ICJncm91cDMiLAogICAgICBlbnNlbWJsICVpbiUgZ3JvdXA0IH4gImdyb3VwNCIsCiAgICAgIGVuc2VtYmwgJWluJSBncm91cDUgfiAiZ3JvdXA1IiwKICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwNiB+ICJncm91cDYiLAogICAgICBlbnNlbWJsICVpbiUgZ3JvdXA3IH4gImdyb3VwNyIsCiAgICAgIGVuc2VtYmwgJWluJSBncm91cDggfiAiZ3JvdXA4IiwKICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwOSB+ICJncm91cDkiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogICkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKIyMgUGxvdCBkaXN0YW5jZQojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMSkgKSRkaXN0YW5jZQojICAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRkaXN0YW5jZQojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KCgpwbG90X1RBRGRpc3RhbmNlIDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgIyBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogICMgcDE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDUiKSwgNSkKICAjIHAxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA4IiksIDUpCiAgIyBwMjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQogICMgcDI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDgiKSwgNSkKICAjIHA1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDUiLCAiZ3JvdXA4IiksIDUpCiAgIyAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlzdGFuY2UpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikKICAgICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxODogIiwgY29udlB2YWx1ZShwMTgpLCAiXG4iLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInA1ODogIixjb252UHZhbHVlKCBwNTgpLCAiXG4iKSwKICAgICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZGlzdGFuY2VfdG9fYm91bmRhcnlfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQoKcGxvdF9UQURkaXN0YW5jZShnZW5lLlRTUy50Yi5wbG90LCAiZ3JvdXBfQTQ4NSIpCgoKIyMgUGxvdCBUQUQgc2l6ZQojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMSkgKSRUQURzaXplCiMgICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAyKSApJFRBRHNpemUKIyAgIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKIyAgIHJldHVybih3aWwkcC52YWx1ZSkKIyB9CiMgCgpwbG90X1RBRHNpemUgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAyMDAwMDAwKXsKICAjIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXAyIiksIDUpCiAgIyBwMTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQogICMgcDE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDgiKSwgNSkKICAjIHAyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA1IiksIDUpCiAgIyBwMjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQogICMgcDU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwNSIsICJncm91cDgiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gVEFEc2l6ZSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBncm91cCksIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKSAKICAgICMgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxODogIiwgY29udlB2YWx1ZShwMTgpLCAiXG4iLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInA1ODogIixjb252UHZhbHVlKCBwNTgpLCAiXG4iKSwKICAgICMgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgic2l6ZV9vZl9ib3VuZGFyeV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMwogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CnBsb3RfVEFEc2l6ZShnZW5lLlRTUy50Yi5wbG90LCAiZ3JvdXBfQTQ4NSIsIHltYXggPSA2ZTYpCmBgYAoKIyMgWzIuMTZdIENoZWNraW5nIHRoZSBpbnRlbnNpdHkgb2YgUkFEMjEgYXQgVEFEIGJvdW5kYXJ5CiMjIyMgQ2FsY3VsYXRpbmcgUkFEMjEgaW50ZW5zaXR5IG9mIHRoZSBuZWFyZXN0IFRBRCBib3VuZGFyeQpgYGB7cn0KcmVmRGlyIDwtIGhlcmUoIi4uLy4uIiwgInJlZmVyZW5jZSIpCgojIEltcG9ydGluZyBUQUQgYm91bmRhcnkKdGFkX2JvdW5kYXJ5IDwtIGZyZWFkKGhlcmUoIi4uLy4uL3Jlc3VsdC9UQUQiLCAiVEFEXzI1a2JfMTI1a2Jfb3RzdV9ib3VuZGFyaWVzX0cxRE1TTy5iZWQiKSkKY29sbmFtZXModGFkX2JvdW5kYXJ5KSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgZHBseXI6Om11dGF0ZSh0YWRfaWQgPSBwYXN0ZShjaHIsIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBzdGFydCAtMTc1MDAwLzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kID0gZW5kICsgMTc1MDAwLzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yKQoKIyBJbXBvcnRpbmcgUkFEMjEgYmlnd2lnIHRyYWNrCmJ3LlJBRDIxIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfdHJpbV9xMjBfZGVkdXBfYmxhY2tfZGVwdGhOb3JtX2JpbjUwYnAuYnciKSkKCiMgQ3JlYXRlIEdSYW5nZXMgb2JqZWN0IGZvciBUQUQgYm91bmRhcmllcwp0YWRfcmFuZ2VzIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0YWRfYm91bmRhcnksIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCgojIEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBhbGwgVEFEIGJvdW5kYXJpZXMgYW5kIFJBRDIxIGJpZ3dpZyBkYXRhCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyh0YWRfcmFuZ2VzLCBidy5SQUQyMSkKCiMgRXh0cmFjdCBvdmVybGFwcGluZyByZWdpb25zIGFuZCBzY29yZXMgZnJvbSB0aGUgQmlnV2lnCm92ZXJsYXBwaW5nX2J3IDwtIGJ3LlJBRDIxW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0Kb3ZlcmxhcHBpbmdfdGFkcyA8LSB0YWRfcmFuZ2VzW3F1ZXJ5SGl0cyhvdmVybGFwcyldCgojIEFnZ3JlZ2F0ZSBzY29yZXMgYnkgVEFEIGJvdW5kYXJ5IHJlZ2lvbnMKCgpzY29yZXMgPC0gYXNfdGliYmxlKG92ZXJsYXBwaW5nX2J3KSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhZF9pZCA9IHRhZF9yYW5nZXNbcXVlcnlIaXRzKG92ZXJsYXBzKV0kdGFkX2lkKSAlPiUKICBncm91cF9ieSh0YWRfaWQpICU+JQogIHN1bW1hcmlzZShyYWQyMVNjb3JlID0gc3VtKHNjb3JlKSkKCnRhZF9ib3VuZGFyeSA8LSB0YWRfYm91bmRhcnkgJT4lCiAgbGVmdF9qb2luKHNjb3JlcywgYnkgPSAidGFkX2lkIikKCgoKCgojIEltcG9ydGluZyBnZW5lCmdlbmUuVFNTLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSkgJT4lCiAgZHBseXI6OnNlbGVjdChWNiwgVjUsIFYxLCBUU1MpCmNvbG5hbWVzKGdlbmUuVFNTLnRiKSA8LSBjKCJlbnNlbWJsIiwgImdlbmUiLCAiY2hyIiwgIlRTUyIpCgoKIyBGaW5kIG5lYXJlc3QgVEFEIGJvdW5kYXJ5CmZpbmRDbG9zZXN0VEFEQm91bmRhcnlJRCA8LSBmdW5jdGlvbihjaHJvbSwgVFNTLCB0YWRfYm91bmRhcnkpewogIHRlbXAgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6ZmlsdGVyKGNociA9PSBjaHJvbSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gYWJzKGNlbnRlciAtIFRTUykpICU+JQogICAgc2xpY2VfbWluKGRpc3RhbmNlKQogIGlmKG5yb3codGVtcCkgPT0gMSl7CiAgICAgIHJldHVybih0ZW1wJHRhZF9pZCkKICB9ZWxzZXsKICAgIHJldHVybihOQSkKICB9Cn0KZ2VuZS5UU1MudGIgPC0gZ2VuZS5UU1MudGIgJT4lIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKGNsb3Nlc3RCb3VuZGFyeSA9IGZpbmRDbG9zZXN0VEFEQm91bmRhcnlJRChjaHIsIFRTUywgdGFkX2JvdW5kYXJ5KSkKCnRlbXAgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6c2VsZWN0KHRhZF9pZCwgcmFkMjFTY29yZSkKCmdlbmUuVFNTLnRiIDwtIGdlbmUuVFNTLnRiICU+JSBsZWZ0X2pvaW4odGVtcCwgYnkgPSBjKCJjbG9zZXN0Qm91bmRhcnkiID0gInRhZF9pZCIpICkKCmBgYAoKCiMjIyMjIFBsb3R0aW5nIGZvciBncm91cHMKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMi50c3YiKSkkZ2VuZQpncm91cDUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpKSRnZW5lCmdyb3VwOCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IikpJGdlbmUKCgpnZW5lLlRTUy50Yi5wbG90IDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDIsICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwNSwgImdyb3VwNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwOCwgImdyb3VwOCIsIE5BKSkpKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgojIyBQbG90IGRpc3RhbmNlCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDEpICkkcmFkMjFTY29yZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDIpICkkcmFkMjFTY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X3JhZDIxU2NvcmVBdEJvdW5kYXJ5IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUpewogIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXAyIiksIDUpCiAgcDE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDUiKSwgNSkKICBwMTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwOCIpLCA1KQogIHAyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA1IiksIDUpCiAgcDI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDgiKSwgNSkKICBwNTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXA1IiwgImdyb3VwOCIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gZ3JvdXAsIHkgPSByYWQyMVNjb3JlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyAKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAyMCArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNTogIiwgY29udlB2YWx1ZShwMTUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE4OiAiLCBjb252UHZhbHVlKHAxOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyODogIiwgY29udlB2YWx1ZShwMjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDU4OiAiLGNvbnZQdmFsdWUoIHA1OCksICJcbiIpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgicmFkMjFTY29yZV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMwogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CgpwbG90X3JhZDIxU2NvcmVBdEJvdW5kYXJ5KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cCIpCgoKYGBgCgoKIyMgWzIuMTddIENoZWNraW5nIHRoZSBkZW5zaXR5IG9mIGdlbmUgLyBlbmhhbmNlciB3aXRoaW4gZGVzaWduYXRlZCBUQUQKIyMjIyBNYWtpbmcgVEFEIGdlbmUgY291bnQKYGBge3J9CiMjIyBJTVBPUlRJTkcgUkVRVUlSRUQgREFUQQojIEltcG9ydGluZyBUQUQKdGFkIDwtIGZyZWFkKGhlcmUoIi4uLy4uL3Jlc3VsdC9UQUQiLCAiVEFEXzI1a2JfMTI1a2Jfb3RzdV9HMURNU08uYmVkcGUiKSkKY29sbmFtZXModGFkKSA8LSBjKCJjaHIxIiwgInN0YXJ0MSIsICJlbmQxIiwgImNocjIiLCAic3RhcnQyIiwgImVuZDIiKQp0YWQgPC0gdGFkICU+JSBkcGx5cjo6bXV0YXRlKHRhZElEID0gcGFzdGUoY2hyMSwgc3RhcnQxLCBlbmQxLCBzZXAgPSAiXyIpKQoKCiMgSW1wb3J0aW5nIGdlbmUKZ2VuZS5UU1MudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpKSAlPiUKICBkcGx5cjo6c2VsZWN0KFY2LCBWNSwgVjEsIFRTUykKY29sbmFtZXMoZ2VuZS5UU1MudGIpIDwtIGMoImVuc2VtYmwiLCAiZ2VuZSIsICJjaHIiLCAiVFNTIikKCiMgSW1wb3J0aW5nIGVuaGFuY2VyCnBlYWsuSDNLMjdhYyA8LSBhc190aWJibGUoaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIkdTTTI0Mzg0NzZfRUMtREctMzQ1OC1IM0syN0FDX0FTWU5fMS5uYXJyb3dQZWFrLmJlZCIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIgPSAoc3RhcnQgKyBlbmQpLzIpCgoKIyMjIEZVTkNUSU9OIEZPUiBDT1VOVElORwpmaW5kSXRzVEFEIDwtIGZ1bmN0aW9uKGNocm9tLCBjb29yZGluYXRlLCB0YWQpewogIHRlbXAgPC0gdGFkICU+JSBkcGx5cjo6ZmlsdGVyKGNocjEgPT0gY2hyb20sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQxIDwgY29vcmRpbmF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQxID4gY29vcmRpbmF0ZSkKICBpZihucm93KHRlbXApID09IDEpewogICAgcmV0dXJuKHRlbXAkdGFkSUQpCiAgfWVsc2V7CiAgICByZXR1cm4oTkEpCiAgfQp9CgojIyMgQ291bnRpbmcgZWFjaCBmZWF0dXJlcyBmb3IgVEFECiMjIyBDb3VudGluZyBnZW5lCmdlbmVDb3VudFBlclRBRCA8LSBnZW5lLlRTUy50YiAlPiUgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUoVEFEID0gZmluZEl0c1RBRChjaHIsIFRTUywgdGFkKSkgJT4lCiAgZHJvcF9uYSgpICU+JQogIGdyb3VwX2J5KFRBRCkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKQoKIyMjIENvdW50aW5nIGVuaGFuY2VyCgplbmhDb3VudFBlclRBRCA8LSBwZWFrLkgzSzI3YWMgJT4lIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRBRCA9IGZpbmRJdHNUQUQoc2VxbmFtZXMsIGNlbnRlciwgdGFkKSkgJT4lCiAgZHJvcF9uYSgpICU+JQogIGdyb3VwX2J5KFRBRCkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKQoKIyMjIEdldCBUQUQgc2l6ZXoKdGFkLmRiIDwtIHRhZCAlPiUgbGVmdF9qb2luKGdlbmVDb3VudFBlclRBRCwgYnkgPSBjKCJ0YWRJRCIgPSAiVEFEIiksICkgJT4lCiAgbGVmdF9qb2luKGVuaENvdW50UGVyVEFELCBieSA9IGMoInRhZElEIiA9ICJUQUQiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDcsIDgsIDkpKSAlPiUKICBtdXRhdGVfYWxsKH5yZXBsYWNlKC4sIGlzLm5hKC4pLCAwKSkKCmNvbG5hbWVzKHRhZC5kYikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJ0YWRJRCIsICJnZW5lQ291bnQiLCAiZW5oQ291bnQiKQoKdGFkLmRiIDwtIHRhZC5kYiAlPiUgZHBseXI6Om11dGF0ZSgKICB0YWRTaXplID0gZW5kIC0gc3RhcnQsCiAgZ2VuZURlbnNpdHkgPSBnZW5lQ291bnQvdGFkU2l6ZSAqIDEwMGUzLAogIGVuaERlbnNpdHkgPSBlbmhDb3VudC90YWRTaXplKiAxMDBlMywKICByZWdEZW5zaXR5ID0gKGdlbmVDb3VudCArIGVuaENvdW50KS90YWRTaXplKiAxMDBlMwopCgoKCiMjIyBBc3NpZ24gVEFEIGFuZCBpbmZvcm1hdGlvbiB0byBnZW5lCmdlbmUuVFNTLnRiIDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lCiAgZHBseXI6Om11dGF0ZShUQUQgPSBmaW5kSXRzVEFEKGNociwgVFNTLCB0YWQpKQojZ2VuZS5UU1MudGIgPC0gZ2VuZS5UU1MudGIgJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFRBRCkpCnRlbXAgPC0gdGFkLmRiICU+JSBkcGx5cjo6c2VsZWN0KC1jKDEsIDIsIDMpKQoKZ2VuZS5UU1MudGIgPC0gZ2VuZS5UU1MudGIgJT4lIGRwbHlyOjpsZWZ0X2pvaW4odGVtcCwgYnkgPSBjKCJUQUQiID0gInRhZElEIikpCmBgYAoKIyMjIyBQbG90dGluZyBmb3IgZ3JvdXBzCiMjIyMjIGdlbmVDb3VudAojIyMjIyMgQmluYXJ5IGdyb3VwCmBgYHtyfQpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCgpnZW5lLlRTUy50Yi5wbG90IDwtIGdlbmUuVFNTLnRiICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoCiAgZ3JvdXAgPSBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMSwgImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDIsICJncm91cDIiLCBOQSkpKSAlPiUgCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKCiMjIGdlbmVDb3VudApnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGdlbmVDb3VudAogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDIpICkkZ2VuZUNvdW50CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfZ2VuZUNvdW50IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZ2VuZUNvdW50KSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJnZW5lQ291bnRfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDEuNQogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CnBsb3RfZ2VuZUNvdW50KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cF9iaW5hcnlHcm91cCIsIHltYXggPSAyMDApCgpgYGAKIyMjIyMjIEdyb3VwCmBgYHtyfQpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDIudHN2IikpJGdlbmUKZ3JvdXA1IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwNS50c3YiKSkkZ2VuZQpncm91cDggPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA4LnRzdiIpKSRnZW5lCgoKZ2VuZS5UU1MudGIucGxvdCA8LSBnZW5lLlRTUy50YiAlPiUgcm93d2lzZSgpICU+JSBkcGx5cjo6bXV0YXRlKAogIGdyb3VwID0gaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDEsICJncm91cDEiLAogICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXAyLCAiZ3JvdXAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDUsICJncm91cDUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVuc2VtYmwgJWluJSBncm91cDgsICJncm91cDgiLCBOQSkpKSkpICU+JSAKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgoKIyMgZ2VuZUNvdW50CmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDEpICkkZ2VuZUNvdW50CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRnZW5lQ291bnQKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKcGxvdF9nZW5lQ291bnQgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAyMDAwMDAwKXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIHAxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiAgcDE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDgiKSwgNSkKICBwMjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQogIHAyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiAgcDU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwNSIsICJncm91cDgiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZ2VuZUNvdW50KSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNTogIiwgY29udlB2YWx1ZShwMTUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE4OiAiLCBjb252UHZhbHVlKHAxOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyODogIiwgY29udlB2YWx1ZShwMjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDU4OiAiLGNvbnZQdmFsdWUoIHA1OCksICJcbiIpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZ2VuZUNvdW50XyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAzCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KcGxvdF9nZW5lQ291bnQoZ2VuZS5UU1MudGIucGxvdCwgImdyb3VwIiwgeW1heCA9IDIwMCkKCmBgYAojIyMjIyBlbmhDb3VudAojIyMjIyMgQmluYXJ5IEdyb3VwCmBgYHtyfQojIyBlbmhDb3VudApnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGVuaENvdW50CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRlbmhDb3VudAogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X2VuaENvdW50IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZW5oQ291bnQpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gKHltaW4gKyB5bWF4KS8yICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpKSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoImVuaENvdW50XyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAxLjUKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQpwbG90X2VuaENvdW50KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cF9iaW5hcnlHcm91cCIsIHltYXggPSAyMDApCgpgYGAKIyMjIyMjIEdyb3VwCmBgYHtyfQojIyBlbmhDb3VudApnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGVuaENvdW50CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRlbmhDb3VudAogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X2VuaENvdW50IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICBwMTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQogIHAxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA4IiksIDUpCiAgcDI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDUiKSwgNSkKICBwMjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQogIHA1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDUiLCAiZ3JvdXA4IiksIDUpCiAgCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSBncm91cCwgeSA9IGVuaENvdW50KSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNTogIiwgY29udlB2YWx1ZShwMTUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE4OiAiLCBjb252UHZhbHVlKHAxOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyODogIiwgY29udlB2YWx1ZShwMjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDU4OiAiLGNvbnZQdmFsdWUoIHA1OCksICJcbiIpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZW5oQ291bnRfIiwgbm90ZSkKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDMKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKfQpwbG90X2VuaENvdW50KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cCIsIHltYXggPSAyMDApCgpgYGAKIyMjIyMgZ2VuZURlbnNpdHkKIyMjIyMjIGJpbmFyeUdyb3VwCmBgYHtyfQojIyBnZW5lRGVuc2l0eQpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGdlbmVEZW5zaXR5CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRnZW5lRGVuc2l0eQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpwbG90X2dlbmVEZW5zaXR5IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMTApewogIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXAyIiksIDUpCiAgCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSAiLiIsIGZpbGwgPSBncm91cCwgeSA9IGdlbmVEZW5zaXR5KSkgKwogICAgIyBTZXQgYXhpcyBsYWJlbHMgKG5vIHgtYXhpcyB0aXRsZSkKICAgIGxhYnMoeCA9IE5VTEwsIHkgPSAiR2VuZSBkZW5zaXR5IHdpdGhpbiBUQUQiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSAocmV2KGMoIiM3Nzc3NzciLCIjRjI4RTJDIikpKSkgKwogICAgIyBWaW9saW4gcGxvdCB3aXRoIGJsYWNrIG91dGxpbmUsIGN1c3RvbWl6ZWQgbGluZSB3aWR0aCBhbmQgZW5kCiAgICBpbnRyb2RhdGF2aXo6Omdlb21fc3BsaXRfdmlvbGluKGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNAogICAgKSArCiAgICAKICAgICMgQm94IHBsb3Qgd2l0aCBjdXN0b21pemVkIGxpbmUgd2lkdGgsIHNxdWFyZSBlbmQsIGFuZCBvdXRsaWVyIHNpemUKICAgIGdlb21fYm94cGxvdCgKICAgICAgd2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgbGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICBvdXRsaWVyLnNoYXBlID0gTkEsICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgKSArCiAgICAKICAgICMgTWVhbiBwb2ludCBpbiBlYWNoIGdyb3VwCiAgICBzdGF0X3N1bW1hcnkoCiAgICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAwLjUsCiAgICAgIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJibGFjayIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoLjMpCiAgICApICsKICAgIAogICAgIyBIb3Jpem9udGFsIGxpbmUgYXQgeSA9IDAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogICAgCiAgICAjIENvb3JkaW5hdGUgbGltaXRzIGFuZCBjdXN0b20geS1heGlzIGxhYmVscwogICAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKHltaW4sIHltYXgpKSArCiAgICAKICAgICMgQW5ub3RhdGUgcC12YWx1ZSB0ZXh0CiAgICBhbm5vdGF0ZSgKICAgICAgInRleHQiLCB4ID0gMSwgeSA9IHltaW4gKyAxLAogICAgICBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMikpLAogICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMKICAgICkgKwogICAgCiAgICAjIFRoZW1lIGN1c3RvbWl6YXRpb24KICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgICApLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgICApLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgICApLAogICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKSsgICAKICAgIGd1aWRlcygKICAgICAgZmlsbCA9IGd1aWRlX2xlZ2VuZCgKICAgICAgICBrZXl3aWR0aCA9IDAuMiwgICMgQWRqdXN0IHRoZSB3aWR0aCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICAgICBrZXloZWlnaHQgPSAwLjIgICMgQWRqdXN0IHRoZSBoZWlnaHQgb2YgdGhlIGxlZ2VuZCBrZXlzCiAgICAgICkpCiAgCiAgCiAgCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJnZW5lRGVuc2l0eV8iLCBub3RlKQogIHdpZHRoIDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCiAgaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KcGxvdF9nZW5lRGVuc2l0eShnZW5lLlRTUy50Yi5wbG90LCAiZ3JvdXBfYmluYXJ5R3JvdXAiLCB5bWF4ID0gOCkKCmBgYAojIyMjIyMgR3JvdXAKYGBge3J9CiMjIGdlbmVEZW5zaXR5CmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSBncm91cDEpICkkZ2VuZURlbnNpdHkKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAyKSApJGdlbmVEZW5zaXR5CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfZ2VuZURlbnNpdHkgPC0gZnVuY3Rpb24odGVtcC50Yiwgbm90ZSwgeW1pbiA9IDAsIHltYXggPSAyMDAwMDAwKXsKICBwMTIgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwMiIpLCA1KQogIHAxNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA1IiksIDUpCiAgcDE4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDgiKSwgNSkKICBwMjUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwNSIpLCA1KQogIHAyOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA4IiksIDUpCiAgcDU4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwNSIsICJncm91cDgiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZ2VuZURlbnNpdHkpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gKHltaW4gKyB5bWF4KS8yICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTg6ICIsIGNvbnZQdmFsdWUocDE4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNTogIiwgY29udlB2YWx1ZShwMjUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwNTg6ICIsY29udlB2YWx1ZSggcDU4KSwgIlxuIiksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJnZW5lRGVuc2l0eV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMwogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CnBsb3RfZ2VuZURlbnNpdHkoZ2VuZS5UU1MudGIucGxvdCwgImdyb3VwIiwgeW1heCA9IDEwKQoKYGBgCiMjIyMjIGVuaERlbnNpdHkKIyMjIyMjIEJpbmFyeSBncm91cApgYGB7cn0KIyMgZW5oRGVuc2l0eQpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGVuaERlbnNpdHkKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAyKSApJGVuaERlbnNpdHkKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKcGxvdF9lbmhEZW5zaXR5IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICAKICBwIDwtIGdncGxvdCh0ZW1wLnRiLCBhZXMoeCA9IGdyb3VwLCB5ID0gZW5oRGVuc2l0eSkpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBncm91cCksIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAoeW1pbiArIHltYXgpLzIgKyAxLCBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMikpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZW5oRGVuc2l0eV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMS41CiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KcGxvdF9lbmhEZW5zaXR5KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cF9iaW5hcnlHcm91cCIsIHltYXggPSAxMCkKCmBgYAojIyMjIyMgR3JvdXAKYGBge3J9CiMjIGVuaERlbnNpdHkKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMSkgKSRlbmhEZW5zaXR5CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRlbmhEZW5zaXR5CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnBsb3RfZW5oRGVuc2l0eSA8LSBmdW5jdGlvbih0ZW1wLnRiLCBub3RlLCB5bWluID0gMCwgeW1heCA9IDIwMDAwMDApewogIHAxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXAyIiksIDUpCiAgcDE1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDUiKSwgNSkKICBwMTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwOCIpLCA1KQogIHAyNSA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDIiLCAiZ3JvdXA1IiksIDUpCiAgcDI4IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDgiKSwgNSkKICBwNTggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXA1IiwgImdyb3VwOCIpLCA1KQogIAogIHAgPC0gZ2dwbG90KHRlbXAudGIsIGFlcyh4ID0gZ3JvdXAsIHkgPSBlbmhEZW5zaXR5KSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9ICh5bWluICsgeW1heCkvMiArIDEsIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAxNTogIiwgY29udlB2YWx1ZShwMTUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE4OiAiLCBjb252UHZhbHVlKHAxOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMjU6ICIsIGNvbnZQdmFsdWUocDI1KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyODogIiwgY29udlB2YWx1ZShwMjgpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDU4OiAiLGNvbnZQdmFsdWUoIHA1OCksICJcbiIpLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZW5oRGVuc2l0eV8iLCBub3RlKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gMwogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CnBsb3RfZW5oRGVuc2l0eShnZW5lLlRTUy50Yi5wbG90LCAiZ3JvdXAiLCB5bWF4ID0gMTApCgpgYGAKIyMjIyMgcmVnZGVuc2l0eQpgYGB7cn0KIyMgcmVnRGVuc2l0eQpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJHJlZ0RlbnNpdHkKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAyKSApJHJlZ0RlbnNpdHkKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKcGxvdF9yZWdEZW5zaXR5IDwtIGZ1bmN0aW9uKHRlbXAudGIsIG5vdGUsIHltaW4gPSAwLCB5bWF4ID0gMjAwMDAwMCl7CiAgcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMSIsICJncm91cDIiKSwgNSkKICBwMTUgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAxIiwgImdyb3VwNSIpLCA1KQogIHAxOCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDEiLCAiZ3JvdXA4IiksIDUpCiAgcDI1IDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcC50YiwgImdyb3VwMiIsICJncm91cDUiKSwgNSkKICBwMjggPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLnRiLCAiZ3JvdXAyIiwgImdyb3VwOCIpLCA1KQogIHA1OCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAudGIsICJncm91cDUiLCAiZ3JvdXA4IiksIDUpCiAgCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSBncm91cCwgeSA9IHJlZ0RlbnNpdHkpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gKHltaW4gKyB5bWF4KS8yICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTg6ICIsIGNvbnZQdmFsdWUocDE4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNTogIiwgY29udlB2YWx1ZShwMjUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwNTg6ICIsY29udlB2YWx1ZSggcDU4KSwgIlxuIiksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJyZWdEZW5zaXR5XyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAzCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KcGxvdF9yZWdEZW5zaXR5KGdlbmUuVFNTLnRiLnBsb3QsICJncm91cCIsIHltYXggPSAxMCkKCmBgYAojIyMjIENoZWNraW5nIFRBRCBhdmVyYWdlIGxvZzJGQwpgYGB7cn0KZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaikKCnRlbXAgPC0gbGVmdF9qb2luKGdlbmUuVFNTLnRiLCBkaWZmLlJOQSwgYnkgPSBjKCJlbnNlbWJsIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGxvZzJGb2xkQ2hhbmdlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoVEFEKSkKCgpkYXRhIDwtIHRlbXAgJT4lIGdyb3VwX2J5KFRBRCkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShhYnNBdmdMb2cyRkMgPSBhYnMobWVhbihsb2cyRm9sZENoYW5nZSkpLAogICAgICAgICAgICAgICAgICAgYXZnTG9nMkZDID0gbWVhbihsb2cyRm9sZENoYW5nZSksCiAgICAgICAgICAgICAgICAgICBnZW5lRGVuc2l0eSA9IG1lYW4oZ2VuZURlbnNpdHkpLAogICAgICAgICAgICAgICAgICAgZW5oRGVuc2l0eSA9IG1lYW4oZW5oRGVuc2l0eSksCiAgICAgICAgICAgICAgICAgICByZWdEZW5zaXR5ID0gbWVhbihyZWdEZW5zaXR5KSkKCmRhdGEkZ2VuZURlbnNpdHlHcm91cCA8LSBjdXQoCiAgZGF0YSRnZW5lRGVuc2l0eSwKICBicmVha3MgPSBxdWFudGlsZShkYXRhJGdlbmVEZW5zaXR5LCBwcm9icyA9IHNlcSgwLCAxLCAwLjIpLCBuYS5ybSA9IFRSVUUpLAogIGluY2x1ZGUubG93ZXN0ID0gVFJVRSwKICBsYWJlbHMgPSBwYXN0ZTAoc2VxKDAsIDgwLCAyMCksICItIiwgc2VxKDIwLCAxMDAsIDIwKSwgIiUiKQopCgpkYXRhJGVuaERlbnNpdHlHcm91cCA8LSBjdXQoCiAgZGF0YSRlbmhEZW5zaXR5LAogIGJyZWFrcyA9IHF1YW50aWxlKGRhdGEkZW5oRGVuc2l0eSwgcHJvYnMgPSBzZXEoMCwgMSwgMC4yKSwgbmEucm0gPSBUUlVFKSwKICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUsCiAgbGFiZWxzID0gcGFzdGUwKHNlcSgwLCA4MCwgMjApLCAiLSIsIHNlcSgyMCwgMTAwLCAyMCksICIlIikKKQoKCiMjIyBQbG90aW5nICBncm91cGluZwoKcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBlbmhEZW5zaXR5R3JvdXAsIHkgPSBlbmhEZW5zaXR5LCBmaWxsID0gZW5oRGVuc2l0eUdyb3VwKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIHF1YW50aWxlKGRhdGEkZW5oRGVuc2l0eSwgMC45OSkpKSArCiAgbGFicyh4ID0gIkVuaGFuY2VyIERlbnNpdHkgR3JvdXAiICwgeSA9ICJUQUQgZW5oYW5jZXIgZGVuc2l0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRDlEOUQ5IiwgIiNCRkJGQkYiLCAiI0E2QTZBNiIsICIjOEM4QzhDIiwgIiM3MzczNzMiKSkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJ0YWRHcm91cF9lbmhEZW5zaXR5IikKd2lkdGggPC0gcGFuZWxTaXplKDEuMikqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdlbmVEZW5zaXR5R3JvdXAsIHkgPSBnZW5lRGVuc2l0eSwgZmlsbCA9IGdlbmVEZW5zaXR5R3JvdXApKSArIAogIGdlb21fYm94cGxvdChjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIHF1YW50aWxlKGRhdGEkZ2VuZURlbnNpdHksIDAuOTkpKSkgKwogIGxhYnMoeCA9ICJHZW5lIERlbnNpdHkgR3JvdXAiICwgeSA9ICJHZW5lIGRlbnNpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzc3Nzc3NyIsICIjOEI3RTY1IiwgIiNBMjg0NTIiLCAiI0MyODg0RCIsICIjRjI4RTJDIikpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKZmlsZU5hbWUgPC0gcGFzdGUwKCJ0YWRHcm91cF9nZW5lRGVuc2l0eSIpCndpZHRoIDwtIDMxKm1tVG9JbmNoCmhlaWdodCA8LSAzOCptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCiMjIyBQbG90dGluZyBkaXN0cmlidXRpb24gLSBlbmgKIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihlbmhEZW5zaXR5R3JvdXAgPT1ncm91cDEpICkkYXZnTG9nMkZDCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGVuaERlbnNpdHlHcm91cCA9PWdyb3VwMikgKSRhdmdMb2cyRkMKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKIyMjIyBBTEwKIyB5bGltIDwtIG1heChhYnMocXVhbnRpbGUoZGF0YSRhdmdMb2cyRkMsIDAuMDEpKSwgYWJzKHF1YW50aWxlKGRhdGEkYXZnTG9nMkZDLCAwLjk5KSkpCiMgcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBlbmhEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZW5oRGVuc2l0eUdyb3VwKSkrIAojICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjEpICsgdGhlbWVfY2xhc3NpYygpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygteWxpbSwgeWxpbSkpICsKIyAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKIyAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNkOWQ5ZDkiLCAiI2JkYmRiZCIsICIjOTY5Njk2IiwgIiM3MzczNzMiLCAiIzUyNTI1MiIpKQojIAojIGZpbGVOYW1lIDwtIHBhc3RlMCgidGFkR3JvdXBfZW5oRGVuc2l0eV9hdmdMb2cyRkMiKQojIGhlaWdodCA8LSAzCiMgd2lkdGggPC0gMwojIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCiMgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKIyBwcmludChwKQojIGRldi5vZmYoKQojIyMjIFVQCmRhdGEucGx1cyA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGF2Z0xvZzJGQyA+IDApCnBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLnBsdXMsICIwLTIwJSIsICIyMC00MCUiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEucGx1cywgIjIwLTQwJSIsICI0MC02MCUiKSwgNSkKcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEucGx1cywgIjQwLTYwJSIsICI2MC04MCUiKSwgNSkKcHMzNCA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEucGx1cywgIjYwLTgwJSIsICI4MC0xMDAlIiksIDUpCgoKCnAgPC0gZ2dwbG90KGRhdGEucGx1cywgYWVzKHggPSBlbmhEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIAogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZW5oRGVuc2l0eUdyb3VwKSwKICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkrIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgbGFicyh4ID0gIkVuaGFuY2VyIGRlbnNpdHkgZ3JvdXAiICwgeSA9ICJhdmcgbG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZW5oRGVuc2l0eUdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Q5RDlEOSIsICIjQkZCRkJGIiwgIiNBNkE2QTYiLCAiIzhDOEM4QyIsICIjNzM3MzczIikpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxLjUpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDEsIGxhYmVsID0gcGFzdGUwKCJwczAxOiAiLCBjb252UHZhbHVlKHBzMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxMjogIiwgY29udlB2YWx1ZShwczEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjM6ICIsIGNvbnZQdmFsdWUocHMyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczM0OiAiLCBjb252UHZhbHVlKHBzMzQpLCAiXG4iKSwgCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAyKQoKCmZpbGVOYW1lIDwtIHBhc3RlMCgidGFkR3JvdXBfZW5oRGVuc2l0eV9hdmdMb2cyRkNfdXAiKQp3aWR0aCA8LSBwYW5lbFNpemUoMS4xNSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjA3KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCiMjIyMgRE9XTgpkYXRhLm1pbnVzIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoYXZnTG9nMkZDIDwgMCkKcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEubWludXMsICIwLTIwJSIsICIyMC00MCUiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEubWludXMsICIyMC00MCUiLCAiNDAtNjAlIiksIDUpCnBzMjMgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLm1pbnVzLCAiNDAtNjAlIiwgIjYwLTgwJSIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5taW51cywgIjYwLTgwJSIsICI4MC0xMDAlIiksIDUpCgoKcCA8LSBnZ3Bsb3QoZGF0YS5taW51cywgYWVzKHggPSBlbmhEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIAogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZW5oRGVuc2l0eUdyb3VwKSwKICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkrIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgbGFicyh4ID0gIkVuaGFuY2VyIGRlbnNpdHkgZ3JvdXAiICwgeSA9ICJhdmcgbG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZW5oRGVuc2l0eUdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Q5RDlEOSIsICIjQkZCRkJGIiwgIiNBNkE2QTYiLCAiIzhDOEM4QyIsICIjNzM3MzczIikpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkrIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMS41LCAwKSkrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IC0xLCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMikKCmZpbGVOYW1lIDwtIHBhc3RlMCgidGFkR3JvdXBfZW5oRGVuc2l0eV9hdmdMb2cyRkNfZG93biIpCndpZHRoIDwtIHBhbmVsU2l6ZSgxLjE3NSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjA3KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCgojIyMgUGxvdHRpbmcgZGlzdHJpYnV0aW9uIC0gZ2VuZQojIyMjIEFMTAojIHlsaW0gPC0gbWF4KGFicyhxdWFudGlsZShkYXRhJGF2Z0xvZzJGQywgMC4wMSkpLCBhYnMocXVhbnRpbGUoZGF0YSRhdmdMb2cyRkMsIDAuOTkpKSkKIyBwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdlbmVEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ2VuZURlbnNpdHlHcm91cCkpKyAKIyAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIHdpZHRoID0gMC4xKSArIHRoZW1lX2NsYXNzaWMoKSArCiMgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLXlsaW0sIHlsaW0pKSArCiMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiMgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjZDlkOWQ5IiwgIiNiZGJkYmQiLCAiIzk2OTY5NiIsICIjNzM3MzczIiwgIiM1MjUyNTIiKSkKIyAKIyBmaWxlTmFtZSA8LSBwYXN0ZTAoInRhZEdyb3VwX2dlbmVEZW5zaXR5X2F2Z0xvZzJGQyIpCiMgaGVpZ2h0IDwtIDMKIyB3aWR0aCA8LSAzCiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKIyBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCiBnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZURlbnNpdHlHcm91cCA9PWdyb3VwMSkgKSRhdmdMb2cyRkMKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZURlbnNpdHlHcm91cCA9PWdyb3VwMikgKSRhdmdMb2cyRkMKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgoKZGF0YS5wbHVzIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoYXZnTG9nMkZDID4gMCkKcHMwMSA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEucGx1cywgIjAtMjAlIiwgIjIwLTQwJSIpLCA1KQpwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5wbHVzLCAiMjAtNDAlIiwgIjQwLTYwJSIpLCA1KQpwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5wbHVzLCAiNDAtNjAlIiwgIjYwLTgwJSIpLCA1KQpwczM0IDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5wbHVzLCAiNjAtODAlIiwgIjgwLTEwMCUiKSwgNSkKCgoKcCA8LSBnZ3Bsb3QoZGF0YS5wbHVzLCBhZXMoeCA9IGdlbmVEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIAogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ2VuZURlbnNpdHlHcm91cCksCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogIGxhYnMoeCA9ICJHZW5lIGRlbnNpdHkgZ3JvdXAiICwgeSA9ICJhdmcgbG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZ2VuZURlbnNpdHlHcm91cCksIGZ1biA9IG1lYW4sCiAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDEsCiAgICBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMS41KSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAxLCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiksIAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMikKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoInRhZEdyb3VwX2dlbmVEZW5zaXR5X2F2Z0xvZzJGQ191cCIpCndpZHRoIDwtIHBhbmVsU2l6ZSgxLjE1KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuMDcpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIyMjIyBET1dOCmRhdGEubWludXMgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihhdmdMb2cyRkMgPCAwKQpwczAxIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5taW51cywgIjAtMjAlIiwgIjIwLTQwJSIpLCA1KQpwczEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3goZGF0YS5taW51cywgIjIwLTQwJSIsICI0MC02MCUiKSwgNSkKcHMyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KGRhdGEubWludXMsICI0MC02MCUiLCAiNjAtODAlIiksIDUpCnBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveChkYXRhLm1pbnVzLCAiNjAtODAlIiwgIjgwLTEwMCUiKSwgNSkKCgpwIDwtIGdncGxvdChkYXRhLm1pbnVzLCBhZXMoeCA9IGdlbmVEZW5zaXR5R3JvdXAsIHkgPSBhdmdMb2cyRkMpKSArIAogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ2VuZURlbnNpdHlHcm91cCksCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCkgKwogIGxhYnMoeCA9ICJHZW5lIGRlbnNpdHkgZ3JvdXAiICwgeSA9ICJhdmcgbG9nMihmb2xkIGNoYW5nZSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZ2VuZURlbnNpdHlHcm91cCksIGZ1biA9IG1lYW4sCiAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDEsCiAgICBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNEOUQ5RDkiLCAiI0JGQkZCRiIsICIjQTZBNkE2IiwgIiM4QzhDOEMiLCAiIzczNzM3MyIpKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEuNSwgMCkpKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAtMSwgbGFiZWwgPSBwYXN0ZTAoInBzMDE6ICIsIGNvbnZQdmFsdWUocHMwMSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczEyOiAiLCBjb252UHZhbHVlKHBzMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMyMzogIiwgY29udlB2YWx1ZShwczIzKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMzQ6ICIsIGNvbnZQdmFsdWUocHMzNCksICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDIpCgpmaWxlTmFtZSA8LSBwYXN0ZTAoInRhZEdyb3VwX2dlbmVEZW5zaXR5X2F2Z0xvZzJGQ19kb3duIikKd2lkdGggPC0gcGFuZWxTaXplKDEuMTc1KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuMDcpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIyMjIENERiBwbG90Cgprc19yZXN1bHQgPC0ga3MudGVzdCgKICBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVEZW5zaXR5R3JvdXAgPT0gIjAtMjAlIikgJT4lIHB1bGwoYWJzQXZnTG9nMkZDKSwKICBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVEZW5zaXR5R3JvdXAgPT0gIjIwLTQwJSIpICU+JSBwdWxsKGFic0F2Z0xvZzJGQykKKQoKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gYWJzQXZnTG9nMkZDLCBjb2xvciA9IGdlbmVEZW5zaXR5R3JvdXApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkpICsKICBzdGF0X2VjZGYoc2l6ZSA9IDAuNCwgbGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiICkgKyAjIFVzZSBzdGF0X2VjZGYgdG8gcGxvdCB0aGUgZW1waXJpY2FsIENERgogIGxhYnMoCiAgICB4ID0gIkFicy4gbG9nMihmb2xkIGNoYW5nZSkiLAogICAgeSA9ICJDdW11bGF0aXZlIFByb2JhYmlsaXR5IgogICkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMS41KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICMgQ2xlYW4gdGhlbWUKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgICkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xKSkKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoInRhZEdyb3VwX2dlbmVEZW5zaXR5X2F2Z0xvZzJGQ19jZGYiKQp3aWR0aCA8LSAzMyptbVRvSW5jaApoZWlnaHQgPC0zMyptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKZGF0YSA8LSBkYXRhLm1pbnVzCgpncm91cDFfZGF0YSA8LSBkYXRhJGFic0F2Z0xvZzJGQ1tkYXRhJGdlbmVEZW5zaXR5R3JvdXAgPT0gIjAtMjAlIl0KZ3JvdXAyX2RhdGEgPC0gZGF0YSRhYnNBdmdMb2cyRkNbZGF0YSRnZW5lRGVuc2l0eUdyb3VwID09ICIyMC00MCUiXQprcy50ZXN0KGdyb3VwMV9kYXRhLCBncm91cDJfZGF0YSkKCmdyb3VwMV9kYXRhIDwtIGRhdGEkYWJzQXZnTG9nMkZDW2RhdGEkZ2VuZURlbnNpdHlHcm91cCA9PSAiMjAtNDAlIl0KZ3JvdXAyX2RhdGEgPC0gZGF0YSRhYnNBdmdMb2cyRkNbZGF0YSRnZW5lRGVuc2l0eUdyb3VwID09ICI0MC02MCUiXQprcy50ZXN0KGdyb3VwMV9kYXRhLCBncm91cDJfZGF0YSkKCmdyb3VwMV9kYXRhIDwtIGRhdGEkYWJzQXZnTG9nMkZDW2RhdGEkZ2VuZURlbnNpdHlHcm91cCA9PSAiNDAtNjAlIl0KZ3JvdXAyX2RhdGEgPC0gZGF0YSRhYnNBdmdMb2cyRkNbZGF0YSRnZW5lRGVuc2l0eUdyb3VwID09ICI2MC04MCUiXQprcy50ZXN0KGdyb3VwMV9kYXRhLCBncm91cDJfZGF0YSkKCmdyb3VwMV9kYXRhIDwtIGRhdGEkYWJzQXZnTG9nMkZDW2RhdGEkZ2VuZURlbnNpdHlHcm91cCA9PSAiNjAtODAlIl0KZ3JvdXAyX2RhdGEgPC0gZGF0YSRhYnNBdmdMb2cyRkNbZGF0YSRnZW5lRGVuc2l0eUdyb3VwID09ICI4MC0xMDAlIl0Ka3MudGVzdChncm91cDFfZGF0YSwgZ3JvdXAyX2RhdGEpCgoKYGBgCgoKIyMgWzIuMThdIENvbXBhcmluZyBUQUQgaW5zdWxhdGlvbiBzY29yZSBhY3Jvc3Mgc2FtcGxlcwpDaGVja2luZyBob3cgaW5zdWxhdGlvbiBzY29yZSBjaGFuZ2VzIGJ5IHRyZWF0bWVudCBhdCBETVNPIFRBRCBib3VuZGFyaWVzCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5Igpjb25zZW5zdXMubG9vcC5hbm5vLnRiIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCgojIEltcG9ydCBpbnN1bGF0aW9uIHNjb3JlIGNhbGN1bGF0ZWQgd2l0aCBweXRob24KcmVzdWx0RGlyIDwtIGhlcmUoIi4uLy4uL3Jlc3VsdCIpCmluc1Njb3JlLkRNU08gPC0gZnJlYWQoaGVyZShyZXN1bHREaXIsICJUQUQiLCAiaW5zdWxhdGlvblNjb3JlXzI1a2JfRzFETVNPLnRzdiIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAibG9nMl9pbnN1bGF0aW9uX3Njb3JlXzEyNTAwMCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGJpbklEID0gcGFzdGUoY2hyb20sIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIikpCmNvbG5hbWVzKGluc1Njb3JlLkRNU08pIDwtIGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJpbnN1bGF0aW9uU2NvcmUiLCAiYmluSUQiKQppbnNTY29yZS5kVEFHIDwtIGZyZWFkKGhlcmUocmVzdWx0RGlyLCAiVEFEIiwgImluc3VsYXRpb25TY29yZV8yNWtiX0cxZFRBRy50c3YiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImxvZzJfaW5zdWxhdGlvbl9zY29yZV8xMjUwMDAiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShiaW5JRCA9IHBhc3RlKGNocm9tLCBzdGFydCwgZW5kLCBzZXAgPSAiXyIpKQpjb2xuYW1lcyhpbnNTY29yZS5kVEFHKSA8LSBjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAiaW5zdWxhdGlvblNjb3JlIiwgImJpbklEIikKaW5zU2NvcmUuQTQ4NSA8LSBmcmVhZChoZXJlKHJlc3VsdERpciwgIlRBRCIsICJpbnN1bGF0aW9uU2NvcmVfMjVrYl9HMUE0ODUudHN2IikpICU+JSAKICBkcGx5cjo6c2VsZWN0KGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJsb2cyX2luc3VsYXRpb25fc2NvcmVfMTI1MDAwIikpICU+JQogIGRwbHlyOjptdXRhdGUoYmluSUQgPSBwYXN0ZShjaHJvbSwgc3RhcnQsIGVuZCwgc2VwID0gIl8iKSkKY29sbmFtZXMoaW5zU2NvcmUuQTQ4NSkgPC0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImluc3VsYXRpb25TY29yZSIsICJiaW5JRCIpCgpnZXRJbnN1bGF0aW9uU2NvcmUgPC0gZnVuY3Rpb24oY2hyLCBjb29yZGluYXRlLCBpbnNTY29yZS50Yil7CiAgdGVtcC50YiA8LSBpbnNTY29yZS50YiAlPiUgZHBseXI6OmZpbHRlcihjaHJvbSA9PSBjaHIsIHN0YXJ0IDwgY29vcmRpbmF0ZSwgZW5kID4gY29vcmRpbmF0ZSkKICBvdXQgPC0gdGVtcC50YiRpbnN1bGF0aW9uU2NvcmUKICBpZihsZW5ndGgob3V0KSA8IDEpewogICAgcmV0dXJuKE5BKQogIH1lbHNlewogICAgcmV0dXJuKHRlbXAudGIkaW5zdWxhdGlvblNjb3JlKQogIH0KfQoKIyBJbXBvcnRpbmcgVEFEIGJvdW5kYXJpZXMKdGFkX2JvdW5kYXJ5IDwtIGZyZWFkKGhlcmUoIi4uLy4uL3Jlc3VsdC9UQUQiLCAiVEFEXzI1a2JfMTI1a2Jfb3RzdV9ib3VuZGFyaWVzX0cxRE1TTy5iZWQiKSkKY29sbmFtZXModGFkX2JvdW5kYXJ5KSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUodGFkX2lkID0gcGFzdGUoY2hyLCBzdGFydCwgZW5kLCBzZXAgPSAiXyIpLAogICAgICAgICAgICAgICAgY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yLAogICAgICAgICAgICAgICAgaW5zU2NvcmVfRE1TTyA9IGdldEluc3VsYXRpb25TY29yZShjaHIsIGNlbnRlciwgaW5zU2NvcmUuRE1TTyksCiAgICAgICAgICAgICAgICBpbnNTY29yZV9kVEFHID0gZ2V0SW5zdWxhdGlvblNjb3JlKGNociwgY2VudGVyLCBpbnNTY29yZS5kVEFHKSwKICAgICAgICAgICAgICAgIGluc1Njb3JlX0E0ODUgPSBnZXRJbnN1bGF0aW9uU2NvcmUoY2hyLCBjZW50ZXIsIGluc1Njb3JlLkE0ODUpKQoKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgZmlsdGVyKCFpZl9hbnkoZXZlcnl0aGluZygpLCBpcy5uYSkpCgp0YWRfYm91bmRhcnkkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0YWRfYm91bmRhcnkkaW5zU2NvcmVfRE1TTywgdGFkX2JvdW5kYXJ5JGluc1Njb3JlX2RUQUcsIG4gPSAxMDApCnRhZF9ib3VuZGFyeSA8LSB0YWRfYm91bmRhcnkgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmdncGxvdCh0YWRfYm91bmRhcnksIGFlcyh4ID0gaW5zU2NvcmVfRE1TTywgeSA9IGluc1Njb3JlX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArIGNvb3JkX2ZpeGVkKCkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKyB0aGVtZV9idygpCgoKCnRhZF9ib3VuZGFyeSRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRhZF9ib3VuZGFyeSRpbnNTY29yZV9ETVNPLCB0YWRfYm91bmRhcnkkaW5zU2NvcmVfQTQ4NSwgbiA9IDEwMCkKdGFkX2JvdW5kYXJ5IDwtIHRhZF9ib3VuZGFyeSAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZ2dwbG90KHRhZF9ib3VuZGFyeSwgYWVzKHggPSBpbnNTY29yZV9ETVNPLCB5ID0gaW5zU2NvcmVfQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsgY29vcmRfZml4ZWQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArIHRoZW1lX2J3KCkKCgoKCmBgYAoKCiMjIFsyLjIwXSBDaGVja2luZyBob3cgbWFueSBsb29wcyBjcm9zcyB0aGUgYm91bmRhcnk/ClByZXZpb3VzbHksIEkgdHJpZWQgdG8gY2hlY2sgdGhlIHBlcmNlbnRhZ2Ugb2YgbG9vcHMgY3Jvc3NpbmcgdGhlIGJvdW5kYXJ5IHBlciBncm91cCB3aGljaCB3YXNuJ3QgZnJ1aXRmdWwuClRoaXMgdGltZSwgdHJ5IHRvIGRvIHRoaXMgb24gdGhlIGRpZmZlcmVudGlhbCBsb29wcy4KIyMjIyBkVEFHCmBgYHtyfQojIyMgSW1wb3J0aW5nIGRpZmZlcmVudGlhbCByZWd1bGF0b3J5IGxvb3BzCgpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShncm91cCA9ICJVUC9OTyIpCmNvbG5hbWVzKGxvb3AudXApIDwtIGMoImNocjEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyMiIsICJzdGFydDIiLCAiZW5kMiIsICJncm91cCIpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIlVQL05PIikKY29sbmFtZXMobG9vcC5ubykgPC0gYygiY2hyMSIsICJzdGFydDEiLCAiZW5kMSIsICJjaHIyIiwgInN0YXJ0MiIsICJlbmQyIiwgImdyb3VwIikKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkRPV04iKQpjb2xuYW1lcyhsb29wLmRvd24pIDwtIGMoImNocjEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyMiIsICJzdGFydDIiLCAiZW5kMiIsICJncm91cCIpCgpsb29wcyA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKGxvb3AudXAsIGxvb3Aubm8pLCBsb29wLmRvd24pCgojIyMgSW1wb3J0aW5nIFRBRCBib3VuZGFyeQp0YWRfYm91bmRhcnkgPC0gZnJlYWQoaGVyZSgiLi4vLi4vcmVzdWx0L1RBRCIsICJUQURfMjVrYl8xMjVrYl9vdHN1X2JvdW5kYXJpZXNfRzFETVNPLmJlZCIpKQpjb2xuYW1lcyh0YWRfYm91bmRhcnkpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQp0YWRfYm91bmRhcnkgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6bXV0YXRlKHRhZF9pZCA9IHBhc3RlKGNociwgc3RhcnQsIGVuZCwgc2VwID0gIl8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0IC0xNzUwMDAvMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQgPSBlbmQgKyAxNzUwMDAvMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXIgPSAoc3RhcnQgKyBlbmQpLzIpCiMjIyBGdW5jdGlvbnMKY2hlY2tCb3VuZGFyeUNyb3NzIDwtIGZ1bmN0aW9uKGNocm9tMSwgc3RhcnQxLCBlbmQyLCB0YWRfYm91bmRhcnkpewogIHRlbXAgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6ZmlsdGVyKGNociA9PSBjaHJvbTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlciA+IHN0YXJ0MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyIDwgZW5kMikKICByZXR1cm4obGVuZ3RoKHRlbXAkY2VudGVyKSkKfQoKIyMjIENoZWNrIG92ZXJsYXAKbG9vcHMgPC0gbG9vcHMgJT4lIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKGJvdW5kYXJ5Q3Jvc3MgPSBjaGVja0JvdW5kYXJ5Q3Jvc3MoY2hyMSwgc3RhcnQxLCBlbmQyLCB0YWRfYm91bmRhcnkpKQoKIyMjIFBsb3R0aW5nCnN1bW1hcnlfZGF0YSA8LSBsb29wcyAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgc3VtbWFyaXNlKHBlcmNlbnRhZ2UgPSBtZWFuKGJvdW5kYXJ5Q3Jvc3MgPiAwKSAqIDEwMCkKCnN1bW1hcnlfZGF0YSRncm91cCA8LSBmYWN0b3Ioc3VtbWFyeV9kYXRhJGdyb3VwLCBsZXZlbHMgPSBjKCJVUC9OTyIsICJET1dOIikpCgpwIDwtIGdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBwZXJjZW50YWdlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gZGFya2VuKHN0cm9uZ19ncmVlbiwgYW1vdW50ID0gMC4yKSkgKwogIGxhYnMoeSA9ICIlIG9mIGxvb3BzIGNyb3NzaW5nIFRBRCBib3VuZGFyeSIsIHggPSBOVUxMKSArCiAgdGhlbWVfY2xhc3NpYygpICsgeWxpbSgwLCAxMDApICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICkKCmZpbGVOYW1lIDwtIHBhc3RlMCgiYm91bmRhcnlDcm9zc1JhdGlvIikKd2lkdGggPC0gcGFuZWxTaXplKDEpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMgQTQ4NQpgYGB7cn0KIyMjIEltcG9ydGluZyBkaWZmZXJlbnRpYWwgcmVndWxhdG9yeSBsb29wcwpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShncm91cCA9ICJ1cCIpCmNvbG5hbWVzKGxvb3AudXApIDwtIGMoImNocjEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyMiIsICJzdGFydDIiLCAiZW5kMiIsICJncm91cCIpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0E0ODV2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIm5vIikKY29sbmFtZXMobG9vcC5ubykgPC0gYygiY2hyMSIsICJzdGFydDEiLCAiZW5kMSIsICJjaHIyIiwgInN0YXJ0MiIsICJlbmQyIiwgImdyb3VwIikKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gImRvd24iKQpjb2xuYW1lcyhsb29wLmRvd24pIDwtIGMoImNocjEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyMiIsICJzdGFydDIiLCAiZW5kMiIsICJncm91cCIpCgpsb29wcyA8LSBiaW5kX3Jvd3MoYmluZF9yb3dzKGxvb3AudXAsIGxvb3Aubm8pLCBsb29wLmRvd24pCgojIyMgSW1wb3J0aW5nIFRBRCBib3VuZGFyeQp0YWRfYm91bmRhcnkgPC0gZnJlYWQoaGVyZSgiLi4vLi4vcmVzdWx0L1RBRCIsICJUQURfMjVrYl8xMjVrYl9vdHN1X2JvdW5kYXJpZXNfRzFETVNPLmJlZCIpKQpjb2xuYW1lcyh0YWRfYm91bmRhcnkpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQp0YWRfYm91bmRhcnkgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6bXV0YXRlKHRhZF9pZCA9IHBhc3RlKGNociwgc3RhcnQsIGVuZCwgc2VwID0gIl8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0IC0xNzUwMDAvMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQgPSBlbmQgKyAxNzUwMDAvMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXIgPSAoc3RhcnQgKyBlbmQpLzIpCiMjIyBGdW5jdGlvbnMKY2hlY2tCb3VuZGFyeUNyb3NzIDwtIGZ1bmN0aW9uKGNocm9tMSwgc3RhcnQxLCBlbmQyLCB0YWRfYm91bmRhcnkpewogIHRlbXAgPC0gdGFkX2JvdW5kYXJ5ICU+JSBkcGx5cjo6ZmlsdGVyKGNociA9PSBjaHJvbTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlciA+IHN0YXJ0MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyIDwgZW5kMikKICByZXR1cm4obGVuZ3RoKHRlbXAkY2VudGVyKSkKfQoKIyMjIENoZWNrIG92ZXJsYXAKbG9vcHMgPC0gbG9vcHMgJT4lIHJvd3dpc2UoKSAlPiUKICBkcGx5cjo6bXV0YXRlKGJvdW5kYXJ5Q3Jvc3MgPSBjaGVja0JvdW5kYXJ5Q3Jvc3MoY2hyMSwgc3RhcnQxLCBlbmQyLCB0YWRfYm91bmRhcnkpKQoKIyMjIFBsb3R0aW5nCnN1bW1hcnlfZGF0YSA8LSBsb29wcyAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgc3VtbWFyaXNlKHBlcmNlbnRhZ2UgPSBtZWFuKGJvdW5kYXJ5Q3Jvc3MgPiAwKSAqIDEwMCkKCgpwIDwtIGdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBwZXJjZW50YWdlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50YWdlIG9mIFJvd3Mgd2l0aCBib3VuZGFyeUNyb3NzID4gMCBwZXIgR3JvdXAiLAogICAgICAgeCA9ICJHcm91cCIsCiAgICAgICB5ID0gIlBlcmNlbnRhZ2UiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgeWxpbSgwLCAxMDApCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImJvdW5kYXJ5Q3Jvc3NSYXRpb19BNDg1IikKaGVpZ2h0IDwtIDMKd2lkdGggPC0gMwpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgojIyBbMi4yMV0gTE9MQSBvbiBkaWZmZXJlbnRpYWwgbG9vcCBhbmNob3JzCiMjIyMjIExPQURJTkcgTE9MQQpgYGB7cn0KIyBMT0FESU5HIExPTEEgREIKbGlicmFyeSgic2ltcGxlQ2FjaGUiKQpsaWJyYXJ5KCJMT0xBIikKbG9sYURCID0gbG9hZFJlZ2lvbkRCKCIvVm9sdW1lcy9VS0pJTl9TU0QvR2Vub21pY3NfMDNfQW5hbHlzaXNfV29ya2luZy9yZWZlcmVuY2UvTE9MQUNvcmVfY2FjaGVkL21tMTAiKQoKIyBGVU5DVElPTlMKZXh0cmFjdEFuY2hvciA8LSBmdW5jdGlvbihsb29wKXsKICBhbmNob3IxIDwtIGxvb3AgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKICBjb2xuYW1lcyhhbmNob3IxKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICBhbmNob3IyIDwtIGxvb3AgJT4lIGRwbHlyOjpzZWxlY3QoYyg0LCA1LCA2KSkKICBjb2xuYW1lcyhhbmNob3IyKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICBhbmNob3JzIDwtIHJlZHVjZShtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoYmluZF9yb3dzKGFuY2hvcjEsIGFuY2hvcjIpKSkKICAgIHJldHVybihhbmNob3JzKQp9CgpgYGAKIyMjIyBkVEFHLCBDb21wYXJpbmcgdG8gQXN5bmMKIyMjIyMgLSBMaW1pdGVkIHRvIEFUQUMtc2VxIHNpZ25hbCwgcmVnIGxvb3AgYmFja2dyb3VwZApgYGB7cn0KYXRhYyA8LSBmcmVhZChoZXJlKHJlZkRpciwgIkdTTTMxMDYyNTdfQVRBQ19FU0NfMS5iZWQiKSkgJT4lIGRwbHlyOjpzZWxlY3QoVjEsIFYyLCBWMykKY29sbmFtZXMoYXRhYykgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCmF0YWMuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGF0YWMpCgojIExPQURJTkcgTE9PUFMKIyMjIEltcG9ydGluZyBkaWZmZXJlbnRpYWwgcmVndWxhdG9yeSBsb29wcyAmIGV4dHJhY3QgYW5jaG9yCmxvb3AuYWxsIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeS50c3YiKSkgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKQphbmNob3IuYWxsIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuYWxsKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5hbGwsIGF0YWMuZ3IpCmFuY2hvci5hbGwgPC0gcGludGVyc2VjdChhbmNob3IuYWxsW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKCmxvb3AuMSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfRzF2c0FzeW5jX2JvdGhSZXRhaW5lZC5iZWRwZSIpKQphbmNob3IuMSA8LSAoZXh0cmFjdEFuY2hvcihsb29wLjEpKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLjEsIGF0YWMuZ3IpCmFuY2hvci4xIDwtIHBpbnRlcnNlY3QoYW5jaG9yLjFbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmxvb3AuMiA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfRzF2c0FzeW5jX0FzeW5jU3BlY2lmaWNQZXJ0LmJlZHBlIikpCmFuY2hvci4yIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuMikpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuMiwgYXRhYy5ncikKYW5jaG9yLjIgPC0gcGludGVyc2VjdChhbmNob3IuMltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC4zIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9HMXZzQXN5bmNfRzFTcGVjaWZpY1BlcnQuYmVkcGUiKSkKYW5jaG9yLjMgPC0gKGV4dHJhY3RBbmNob3IobG9vcC4zKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci4zLCBhdGFjLmdyKQphbmNob3IuMyA8LSBwaW50ZXJzZWN0KGFuY2hvci4zW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLjQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0cxdnNBc3luY19ib3RoUGVydC5iZWRwZSIpKQphbmNob3IuNCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLjQpKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLjQsIGF0YWMuZ3IpCmFuY2hvci40IDwtIHBpbnRlcnNlY3QoYW5jaG9yLjRbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCgphbmNob3JzIDwtIGxpc3QoYW5jaG9yLjEsIGFuY2hvci4yLCBhbmNob3IuMywgYW5jaG9yLjQpCnRicyA8LSBsaXN0KCkKdGVtcHMgPC0gbGlzdCgpCgojIFByb2Nlc3MgY2x1c3RlcnMgYzEgdG8gYzgKZm9yIChpIGluIDE6NCkgewogIAogIGFuY2hvciA8LSBhbmNob3JzW1tpXV0KICAjIFJ1biBMT0xBCiAgcmVzdWx0IDwtIHJ1bkxPTEEoYW5jaG9yLCBhbmNob3IuYWxsLCBsb2xhREIpCiAgdGIgPC0gYXNfdGliYmxlKHJlc3VsdCkKICAKICAjIEZpbHRlciBhbmQgc3VtbWFyaXplCiAgdGIgPC0gdGIgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICAgIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogICAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQogIAogICMgU3RvcmUgdGIKICB0YnNbW2ldXSA8LSB0YgogIAogICMgU2VsZWN0IGFuZCByZW5hbWUgb2Rkc1JhdGlvCiAgdGVtcCA8LSB0YiAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKICBjb2xuYW1lcyh0ZW1wKSA8LSBjKCJ0YXJnZXQiLCBwYXN0ZTAoIk9SX2MiLCBpKSkKICAKICAjIFN0b3JlIHRlbXAKICB0ZW1wc1tbaV1dIDwtIHRlbXAKfQoKIyBNZXJnZSBhbGwgdGVtcCB0YWJsZXMgaW50byBvbmUKdGVtcCA8LSBSZWR1Y2UoZnVuY3Rpb24oeCwgeSkgZnVsbF9qb2luKHgsIHksIGJ5ID0gInRhcmdldCIpLCB0ZW1wcykgJT4lCiAgbXV0YXRlX2FsbCh+cmVwbGFjZV9uYSguLCAxKSkKY29sbmFtZXModGVtcCkgPC0gYygidGFyZ2V0IiwgImJvdGhSZXRhaW5lZCIsICJBc3luY1NwZWNpZmljUGVydHVyYiIsICJHMVNwZWNpZmljUGVydHVyYiIsICJib3RoUGVydHVyYiIpCmRhdGEgPC0gdGVtcCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJ0YXJnZXQiKSAlPiUgYXMubWF0cml4KCkKCmxpYnJhcnkoY2lyY2xpemUpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDEsIG1heChkYXRhKSksIGMoIndoaXRlIiwgInJlZCIpKQoKCiNmdml6X25iY2x1c3QoZGF0YSwga21lYW5zLCBtZXRob2QgPSAid3NzIikKCnAgPC0gSGVhdG1hcCgKICBkYXRhLAogIG5hbWUgPSAiT2RkcyBSYXRpbyIsICAgICAgICAgICAgICAgICAgICMgTmFtZSBvZiB0aGUgaGVhdG1hcCBsZWdlbmQKICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwgICAgICAgICAgICAjIFJlbW92ZSBjb2x1bW4gZGVuZHJvZ3JhbQogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBjb2wgPSBjb2xfZnVuLAogIGJvcmRlciA9IFRSVUUKKQoKCgpgYGAKCiMjIyMgZFRBRwojIyMjIyAtIExpbWl0aW5nIHRvIEFUQUMtc2VxIHNpZ25hbCwgcmVnIGxvb3AgYmFja2dyb3VuZApgYGB7cn0KYXRhYyA8LSBmcmVhZChoZXJlKHJlZkRpciwgIkdTTTMxMDYyNTdfQVRBQ19FU0NfMS5iZWQiKSkgJT4lIGRwbHlyOjpzZWxlY3QoVjEsIFYyLCBWMykKY29sbmFtZXMoYXRhYykgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCmF0YWMuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGF0YWMpCgojIExPQURJTkcgTE9PUFMKIyMjIEltcG9ydGluZyBkaWZmZXJlbnRpYWwgcmVndWxhdG9yeSBsb29wcyAmIGV4dHJhY3QgYW5jaG9yCmxvb3AuYWxsIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeS50c3YiKSkgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKQphbmNob3IuYWxsIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuYWxsKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5hbGwsIGF0YWMuZ3IpCmFuY2hvci5hbGwgPC0gcGludGVyc2VjdChhbmNob3IuYWxsW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci51cCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci51cCwgYXRhYy5ncikKYW5jaG9yLnVwIDwtIHBpbnRlcnNlY3QoYW5jaG9yLnVwW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLm5vIDwtIChleHRyYWN0QW5jaG9yKGxvb3Aubm8pKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLm5vLCBhdGFjLmdyKQphbmNob3Iubm8gPC0gcGludGVyc2VjdChhbmNob3Iubm9bcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmxvb3AudXBubyA8LSBiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykKYW5jaG9yLnVwbm8gPC0gKGV4dHJhY3RBbmNob3IobG9vcC51cG5vKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci51cG5vLCBhdGFjLmdyKQphbmNob3IudXBubyA8LSBwaW50ZXJzZWN0KGFuY2hvci51cG5vW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5kb3duIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuZG93bikpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuZG93biwgYXRhYy5ncikKYW5jaG9yLmRvd24gPC0gcGludGVyc2VjdChhbmNob3IuZG93bltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKCgpgYGAKCgpgYGB7cn0KIyBSVU5OSU5HIExPTEEKbG9sYURpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQvbG9sYSIpCmRpci5jcmVhdGUobG9sYURpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgojIFVQCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLnVwLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3VwX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIE5PCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLm5vLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX25vX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIFVQTk8KcmVzdWx0ID0gcnVuTE9MQShhbmNob3IudXBubywgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl91cG5vX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIERPV04KcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuZG93biwgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9kb3duX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgoKIyMjIEhFQVRNQVAKYWxwaGEgPC0gMC4wNQp0Yi51cCA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3VwX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9ub19hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCnRiLmRvd24gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9kb3duX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKCnRlbXAudXAgPC0gdGIudXAgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAudXApIDwtIGMoInRhcmdldCIsICJPUl91cCIpCnRlbXAubm8gPC0gdGIubm8gJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAubm8pIDwtIGMoInRhcmdldCIsICJPUl9ubyIpCnRlbXAuZG93biA8LSB0Yi5kb3duICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmRvd24pIDwtIGMoInRhcmdldCIsICJPUl9kb3duIikKCgp0ZW1wIDwtIGZ1bGxfam9pbihmdWxsX2pvaW4odGVtcC51cCwgdGVtcC5ubywgYnkgPSBjKCJ0YXJnZXQiKSksIHRlbXAuZG93biwgYnkgPSBjKCJ0YXJnZXQiKSkgJT4lIG11dGF0ZV9hbGwofnJlcGxhY2VfbmEoLiwgMSkpCgpkYXRhIDwtIGFzLm1hdHJpeCh0ZW1wWzI6NF0pCnJvd25hbWVzKGRhdGEpIDwtIHRlbXAkdGFyZ2V0CgpsaWJyYXJ5KGNpcmNsaXplKQpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYyhtaW4oZGF0YSksIG1heChkYXRhKSksIGMoIndoaXRlIiwgInJlZCIpKQoKCiNmdml6X25iY2x1c3QoZGF0YSwga21lYW5zLCBtZXRob2QgPSAid3NzIikKCiMgcCA8LSBIZWF0bWFwKAojICAgZGF0YSwKIyAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsICAgICAgICAgICAgICAgICAgICMgTmFtZSBvZiB0aGUgaGVhdG1hcCBsZWdlbmQKIyAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiMgICByb3dfa20gPSA0LCAgICAgICAgICAgICAgICAgICAgICAgICAjIERlZmluZSB0aGUgbnVtYmVyIG9mIGstbWVhbnMgY2x1c3RlcnMgZm9yIHJvd3MgKGFkanVzdCBhcyBuZWVkZWQpCiMgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiMgICBjb2wgPSBjb2xfZnVuICAgICAgICAgICAgICAgICAgICAgICAjIFVzZSB0aGUgcmVkIGdyYWRpZW50IGNvbG9yIHNjYWxlCiMgKQojIAojIGZpbGVOYW1lIDwtIHBhc3RlMCgiYW5jaG9yTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9yZWdBbmNob3JCYWNrZ3JvdW5kX2F0YWMiKQojIGhlaWdodCA8LSA3CiMgd2lkdGggPC0gMy41CiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKIyBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCiMgCgoKIyMjIFZpc3VhbGl6aW5nIHAtdmFsdWUgYW5kIE9SCmFscGhhIDwtIDAuMDUKIyB0Yi51cCA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3VwX2F0YWMudHN2IikpICU+JQojICAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKIyAgICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKIyAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiVVAiKSAlPiUKIyAgIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiMgICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiMgICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCiMgdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9ub19hdGFjLnRzdiIpKSAlPiUKIyAgIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSksCiMgICAgICAgICAgICAgICAgIHFWYWx1ZUxvZyA9IC1sb2cyKHFWYWx1ZSksCiMgICAgICAgICAgICAgICAgIGdyb3VwID0gIk5PIikgJT4lCiMgICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQojICAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQojICAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQoKdGIudXBubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3Vwbm9fYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKICAgICAgICAgICAgICAgIHFWYWx1ZUxvZyA9IC1sb2cxMChxVmFsdWUpLAogICAgICAgICAgICAgICAgZ3JvdXAgPSAiVVAvTk8iKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCmZ3cml0ZSh0Yi51cG5vICU+JSBkcGx5cjo6c2VsZWN0KGMoMjQsIDE2LCAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA0LCAyNSwgNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3LCA4LCA5LCAxMCwgMTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTIsIDEzLCAxNCkpLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3Vwbm9fYXRhY19wdWIudHN2IiksIHNlcCA9ICJcdCIpCgp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfZG93bl9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzEwKHFWYWx1ZSksCiAgICAgICAgICAgICAgICBncm91cCA9ICJET1dOIikgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQpmd3JpdGUodGIuZG93biAlPiUgZHBseXI6OnNlbGVjdChjKDI0LCAxNiwgMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNCwgMjUsIDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNywgOCwgOSwgMTAsIDExLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEyLCAxMywgMTQpKSwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9kb3duX2F0YWNfcHViLnRzdiIpLCBzZXAgPSAiXHQiKQoKCnRlbXAudXBubyA8LSB0Yi51cG5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKCnRlbXAgPC0gYmluZF9yb3dzKHRlbXAudXBubywgdGVtcC5kb3duKQoKIyBvcmRlciA8LSBjKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJVUC9OTyIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCwgCiMgICAgICAgICAgICAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiRE9XTiIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCkKCiMgdGVtcCR0YXJnZXQgPC0gZmFjdG9yKHRlbXAkdGFyZ2V0LCBsZXZlbHMgPSByZXYob3JkZXIpKQp0ZW1wJGdyb3VwIDwtIGZhY3Rvcih0ZW1wJGdyb3VwLCBsZXZlbHMgPSBjKCJVUC9OTyIsICJET1dOIikpCgp0YXJnZXRMaXN0IDwtIGMoIlBPTFIyQSIsICJDVFI5IiwKICAgICAgICAgICAgICAgICJBRkY0IiwgIkVMTDIiLAogICAgICAgICAgICAgICAgIk1FRDEiLCAiTUVEMTIiLAogICAgICAgICAgICAgICAgIlRCUCIsICJUQUYxIiwgIlRBRjMiLAogICAgICAgICAgICAgICAgIkUyRjEiLCAiWVkxIiwgIk5JUEJMIiwgCiAgICAgICAgICAgICAgICAiRVAzMDAiLCAiRFBZMzAiLCAiU0VUREIxIiwKICAgICAgICAgICAgICAgICJSQUQyMSIsICJTTUMxQSIsICJTTUMzIiwgIkNUQ0YiLAogICAgICAgICAgICAgICAgIlNVWjEyIiwgIlBIRjE5IgopCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcih0YXJnZXQgJWluJSB0YXJnZXRMaXN0KQp0ZW1wJHRhcmdldCA8LSBmYWN0b3IodGVtcCR0YXJnZXQsIGxldmVscyA9IHJldih0YXJnZXRMaXN0KSkKCgpxVmFsdWVMb2dNYXggPC0gNTAKdGVtcDIgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShxVmFsdWVMb2cgPSBtaW4ocVZhbHVlTG9nLCBxVmFsdWVMb2dNYXgpKQoKcCA8LSBnZ3Bsb3QodGVtcDIsIGFlcyh4ID0gZ3JvdXAsIHkgPSB0YXJnZXQsIGZpbGwgPSBvZGRzUmF0aW8sIHNpemUgPSBxVmFsdWVMb2cpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCAgICAgICAgIyBFbnN1cmVzIGEgcG9pbnQgd2l0aCBhbiBvdXRsaW5lCiAgICAgICAgICAgICBzdHJva2UgPSAxKnB0VG9NTSAgICAgICMgTGluZSB3aWR0aCBmb3IgdGhlIGJvcmRlcgogICkgKyB0aGVtZV9idygpICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjUsIDIpKSArICAjIFNldCBtaW4gYW5kIG1heCBwb2ludCBzaXplcyBoZXJlCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIiNDQjMzM0EiLAogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxLCAzKSwKICAgICAgICAgICAgICAgICAgICAgIG9vYiA9IHNjYWxlczo6c3F1aXNoLCAjIERlZmluZSBncmFkaWVudCBjb2xvcnMKICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIoCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gMS41LzUuMDgsICAjIEFkanVzdCB3aWR0aCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IDE1LzUuMDggICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgKQogICkgKyAKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKIyBwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGdyb3VwLCB5ID0gdGFyZ2V0LCBjb2xvciA9IHFWYWx1ZUxvZywgc2l6ZSA9IG9kZHNSYXRpbykpICsKIyAgIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyAKIyAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMSwgMykpICsgICMgU2V0IG1pbiBhbmQgbWF4IHBvaW50IHNpemVzIGhlcmUKIyAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLAojICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKIyAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKIyAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICAjIEFkanVzdCBoZWlnaHQgb2YgdGhlIGNvbG9yIGJhcgojICAgICAgICAgICAgICAgICAgICAgICAgKSkgKwojICAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICArCiMgICB0aGVtZSgKIyAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKIyAgICAgICBzaXplID0gZm9udFNpemVTLAojICAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAojICAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiMgICAgICksCiMgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKIyAgICAgICBzaXplID0gZm9udFNpemVTLAojICAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAojICAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiMgICAgICksCiMgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAojICAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiMgICAgICAgaGp1c3QgPSAxLCAgICAgICAjIEFkanVzdCBob3Jpem9udGFsIGp1c3RpZmljYXRpb24KIyAgICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KIyAgICAgKSwKIyAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAojICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAojICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAojICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgojICAgICApLAojICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAojICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAojICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAojICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgojICAgICApLAojICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKIyAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAojICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiMgICApCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImFuY2hvckxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfT1JfcVZhbHVlX3JlZ0FuY2hvckJhY2tncm91bmRfYXRhY191cG5vIikKd2lkdGggPC0gcGFuZWxTaXplKDEuNSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjkpKm1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKCmBgYHtyfQojIyMgMjQxMDE1IFRlc3Rpbmcgb24gc3Vic2V0IG9mIGxvb3BzCmFuY2hvci5jMSA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjEpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzEsIGF0YWMuZ3IpCmFuY2hvci5jMSA8LSBwaW50ZXJzZWN0KGFuY2hvci5jMVtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYW5jaG9yLmMyIDwtIGV4dHJhY3RBbmNob3IobG9vcC5jbHVzdGVyMikKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5jMiwgYXRhYy5ncikKYW5jaG9yLmMyIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmMyW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgphbmNob3IuYzMgPC0gZXh0cmFjdEFuY2hvcihsb29wLmNsdXN0ZXIzKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmMzLCBhdGFjLmdyKQphbmNob3IuYzMgPC0gcGludGVyc2VjdChhbmNob3IuYzNbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmFuY2hvci5jNCA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjQpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzQsIGF0YWMuZ3IpCmFuY2hvci5jNCA8LSBwaW50ZXJzZWN0KGFuY2hvci5jNFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYW5jaG9yLmM1IDwtIGV4dHJhY3RBbmNob3IobG9vcC5jbHVzdGVyNSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5jNSwgYXRhYy5ncikKYW5jaG9yLmM1IDwtIHBpbnRlcnNlY3QoYW5jaG9yLmM1W3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgphbmNob3IuYzYgPC0gZXh0cmFjdEFuY2hvcihsb29wLmNsdXN0ZXI2KQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmM2LCBhdGFjLmdyKQphbmNob3IuYzYgPC0gcGludGVyc2VjdChhbmNob3IuYzZbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmFuY2hvci5jNyA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjcpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzcsIGF0YWMuZ3IpCmFuY2hvci5jNyA8LSBwaW50ZXJzZWN0KGFuY2hvci5jN1txdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYW5jaG9yLmM4IDwtIGV4dHJhY3RBbmNob3IobG9vcC5jbHVzdGVyOCkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5jOCwgYXRhYy5ncikKYW5jaG9yLmM4IDwtIHBpbnRlcnNlY3QoYW5jaG9yLmM4W3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jMSwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jMSA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jMiwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jMiA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jMywgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jMyA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jNCwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jNCA9IGFzX3RpYmJsZShyZXN1bHQpCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmM1LCBhbmNob3IuYWxsLCBsb2xhREIpCnRiLmM1ID0gYXNfdGliYmxlKHJlc3VsdCkKCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmM2LCBhbmNob3IuYWxsLCBsb2xhREIpCnRiLmM2ID0gYXNfdGliYmxlKHJlc3VsdCkKCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmM3LCBhbmNob3IuYWxsLCBsb2xhREIpCnRiLmM3ID0gYXNfdGliYmxlKHJlc3VsdCkKCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmM4LCBhbmNob3IuYWxsLCBsb2xhREIpCnRiLmM4ID0gYXNfdGliYmxlKHJlc3VsdCkKCiMjIyBIRUFUTUFQCmFscGhhIDwtIDAuMDUKdGIuYzEgPC0gdGIuYzEgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5jMiA8LSB0Yi5jMiAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCnRiLmMzIDwtIHRiLmMzICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuYzQgPC0gdGIuYzQgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5jNSA8LSB0Yi5jNSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JQogIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKCnRiLmM2IDwtIHRiLmM2ICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lCiAgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQoKdGIuYzcgPC0gdGIuYzcgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0Yi5jOCA8LSB0Yi5jOCAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JQogIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKCnRlbXAuYzEgPC0gdGIuYzEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzEpIDwtIGMoInRhcmdldCIsICJPUl9jMSIpCnRlbXAuYzIgPC0gdGIuYzIgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzIpIDwtIGMoInRhcmdldCIsICJPUl9jMiIpCnRlbXAuYzMgPC0gdGIuYzMgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzMpIDwtIGMoInRhcmdldCIsICJPUl9jMyIpCnRlbXAuYzQgPC0gdGIuYzQgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzQpIDwtIGMoInRhcmdldCIsICJPUl9jNCIpCnRlbXAuYzUgPC0gdGIuYzUgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzUpIDwtIGMoInRhcmdldCIsICJPUl9jNSIpCnRlbXAuYzYgPC0gdGIuYzYgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzYpIDwtIGMoInRhcmdldCIsICJPUl9jNiIpCnRlbXAuYzcgPC0gdGIuYzcgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzcpIDwtIGMoInRhcmdldCIsICJPUl9jNyIpCnRlbXAuYzggPC0gdGIuYzggJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuYzgpIDwtIGMoInRhcmdldCIsICJPUl9jOCIpCgp0ZW1wIDwtIGZ1bGxfam9pbih0ZW1wLmMxLCB0ZW1wLmMyLCBieSA9ICJ0YXJnZXQiKSAlPiUKICBmdWxsX2pvaW4odGVtcC5jMywgYnkgPSAidGFyZ2V0IikgJT4lCiAgZnVsbF9qb2luKHRlbXAuYzQsIGJ5ID0gInRhcmdldCIpICU+JQogIGZ1bGxfam9pbih0ZW1wLmM1LCBieSA9ICJ0YXJnZXQiKSAlPiUKICBmdWxsX2pvaW4odGVtcC5jNiwgYnkgPSAidGFyZ2V0IikgJT4lCiAgZnVsbF9qb2luKHRlbXAuYzcsIGJ5ID0gInRhcmdldCIpICU+JQogIGZ1bGxfam9pbih0ZW1wLmM4LCBieSA9ICJ0YXJnZXQiKSAlPiUKICBtdXRhdGVfYWxsKH5yZXBsYWNlX25hKC4sIDEpKQoKZGF0YSA8LSB0ZW1wICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoInRhcmdldCIpICU+JSBhcy5tYXRyaXgoKQoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMSwgbWF4KGRhdGEpKSwgYygid2hpdGUiLCAicmVkIikpCgoKI2Z2aXpfbmJjbHVzdChkYXRhLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQoKcCA8LSBIZWF0bWFwKAogIGRhdGEsCiAgbmFtZSA9ICJPZGRzIFJhdGlvIiwgICAgICAgICAgICAgICAgICAgIyBOYW1lIG9mIHRoZSBoZWF0bWFwIGxlZ2VuZAogIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4sCiAgYm9yZGVyID0gVFJVRQopCgoKIyBJbml0aWFsaXplIGxpc3RzIHRvIHN0b3JlIHJlc3VsdHMKYW5jaG9ycyA8LSBsaXN0KCkKdGJzIDwtIGxpc3QoKQp0ZW1wcyA8LSBsaXN0KCkKCiMgUHJvY2VzcyBjbHVzdGVycyBjMSB0byBjOApmb3IgKGkgaW4gMTo0KSB7CiAgIyBFeHRyYWN0IGFuY2hvcgogIGxvb3BfY2x1c3RlciA8LSBnZXQocGFzdGUwKCJsb29wLmNsdXN0ZXIiLCBpKSkKICBhbmNob3IgPC0gZXh0cmFjdEFuY2hvcihsb29wX2NsdXN0ZXIpCiAgCiAgIyBGaW5kIG92ZXJsYXBzIGFuZCBpbnRlcnNlY3QKICBvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLCBhdGFjLmdyKQogIGFuY2hvciA8LSBwaW50ZXJzZWN0KGFuY2hvcltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQogIAogICMgU3RvcmUgYW5jaG9yCiAgYW5jaG9yc1tbaV1dIDwtIGFuY2hvcgogIAogICMgUnVuIExPTEEKICByZXN1bHQgPC0gcnVuTE9MQShhbmNob3IsIGFuY2hvci5hbGwsIGxvbGFEQikKICB0YiA8LSBhc190aWJibGUocmVzdWx0KQogIAogICMgRmlsdGVyIGFuZCBzdW1tYXJpemUKICB0YiA8LSB0YiAlPiUKICAgIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogICAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCiAgCiAgIyBTdG9yZSB0YgogIHRic1tbaV1dIDwtIHRiCiAgCiAgIyBTZWxlY3QgYW5kIHJlbmFtZSBvZGRzUmF0aW8KICB0ZW1wIDwtIHRiICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQogIGNvbG5hbWVzKHRlbXApIDwtIGMoInRhcmdldCIsIHBhc3RlMCgiT1JfYyIsIGkpKQogIAogICMgU3RvcmUgdGVtcAogIHRlbXBzW1tpXV0gPC0gdGVtcAp9CgojIE1lcmdlIGFsbCB0ZW1wIHRhYmxlcyBpbnRvIG9uZQp0ZW1wIDwtIFJlZHVjZShmdW5jdGlvbih4LCB5KSBmdWxsX2pvaW4oeCwgeSwgYnkgPSAidGFyZ2V0IiksIHRlbXBzKSAlPiUKICBtdXRhdGVfYWxsKH5yZXBsYWNlX25hKC4sIDEpKQpkYXRhIDwtIHRlbXAgJT4lIGNvbHVtbl90b19yb3duYW1lcygidGFyZ2V0IikgJT4lIGFzLm1hdHJpeCgpCgpsaWJyYXJ5KGNpcmNsaXplKQpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYygxLCBtYXgoZGF0YSkpLCBjKCJ3aGl0ZSIsICJyZWQiKSkKCgojZnZpel9uYmNsdXN0KGRhdGEsIGttZWFucywgbWV0aG9kID0gIndzcyIpCgpwIDwtIEhlYXRtYXAoCiAgZGF0YSwKICBuYW1lID0gIk9kZHMgUmF0aW8iLCAgICAgICAgICAgICAgICAgICAjIE5hbWUgb2YgdGhlIGhlYXRtYXAgbGVnZW5kCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICAgICAgICAgICAgIyBSZW1vdmUgY29sdW1uIGRlbmRyb2dyYW0KICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgY29sID0gY29sX2Z1biwKICBib3JkZXIgPSBUUlVFCikKYGBgCgoKCiMjIyMjIC0gTGltaXRlZCB0byBBVEFDLXNlcSBzaWduYWwsIGFsbCBsb29wIGJhY2tncm91cApgYGB7cn0KYXRhYyA8LSBmcmVhZChoZXJlKHJlZkRpciwgIkdTTTMxMDYyNTdfQVRBQ19FU0NfMS5iZWQiKSkgJT4lIGRwbHlyOjpzZWxlY3QoVjEsIFYyLCBWMykKY29sbmFtZXMoYXRhYykgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCmF0YWMuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGF0YWMpCgojIExPQURJTkcgTE9PUFMKIyMjIEltcG9ydGluZyBkaWZmZXJlbnRpYWwgcmVndWxhdG9yeSBsb29wcyAmIGV4dHJhY3QgYW5jaG9yCmxvb3AuYWxsIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeS50c3YiKSkKYW5jaG9yLmFsbCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmFsbCkpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYWxsLCBhdGFjLmdyKQphbmNob3IuYWxsIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmFsbFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQphbmNob3IudXAgPC0gKGV4dHJhY3RBbmNob3IobG9vcC51cCkpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IudXAsIGF0YWMuZ3IpCmFuY2hvci51cCA8LSBwaW50ZXJzZWN0KGFuY2hvci51cFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQphbmNob3Iubm8gPC0gKGV4dHJhY3RBbmNob3IobG9vcC5ubykpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3Iubm8sIGF0YWMuZ3IpCmFuY2hvci5ubyA8LSBwaW50ZXJzZWN0KGFuY2hvci5ub1txdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC51cG5vIDwtIGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKQphbmNob3IudXBubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwbm8pKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLnVwbm8sIGF0YWMuZ3IpCmFuY2hvci51cG5vIDwtIHBpbnRlcnNlY3QoYW5jaG9yLnVwbm9bcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCgpsb29wTnVtIDwtIG5yb3cobG9vcC51cG5vKQoKIyBTZWxlY3Rpbmcgc2FtZSBudW1iZXIgb2YgZXh0cmVtZSBkb3duIGxvb3BzCmxvb3AuZG93biA8LSBsb29wLmFsbCAlPiUgZHBseXI6OmZpbHRlcihkaWZmX2RUQUdfRE1TTyA8IC0wLjIpICU+JSBkcGx5cjo6YXJyYW5nZShkaWZmX2RUQUdfRE1TTykgJT4lIHNsaWNlX2hlYWQobiA9IGxvb3BOdW0pCmFuY2hvci5kb3duIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuZG93bikpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuZG93biwgYXRhYy5ncikKYW5jaG9yLmRvd24gPC0gcGludGVyc2VjdChhbmNob3IuZG93bltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYGBgCgoKYGBge3J9CiMgUlVOTklORyBMT0xBCmxvbGFEaXIgPC0gaGVyZSgiLi4vLi4vcmVzdWx0L2xvbGEiKQpkaXIuY3JlYXRlKGxvbGFEaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQoKIyBVUApyZXN1bHQgPSBydW5MT0xBKGFuY2hvci51cCwgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCiNmd3JpdGUodGIsIGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfdXBfYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyBOTwpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5ubywgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCiNmd3JpdGUodGIsIGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfbm9fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyBVUE5PCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLnVwbm8sIGFuY2hvci5hbGwsIGxvbGFEQikKdGIgPSBhc190aWJibGUocmVzdWx0KQojZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3Vwbm9fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKCiMgRE9XTgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5kb3duLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKI2Z3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9kb3duX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSwgc2VwID0gIlx0IikKCgoKIyMjIEhFQVRNQVAKYWxwaGEgPC0gMC4wNQp0Yi51cCA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3VwX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5ubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX25vX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfZG93bl9hbGxMb29wc19leHRyZW1lX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKCnRlbXAudXAgPC0gdGIudXAgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAudXApIDwtIGMoInRhcmdldCIsICJPUl91cCIpCnRlbXAubm8gPC0gdGIubm8gJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAubm8pIDwtIGMoInRhcmdldCIsICJPUl9ubyIpCnRlbXAuZG93biA8LSB0Yi5kb3duICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmRvd24pIDwtIGMoInRhcmdldCIsICJPUl9kb3duIikKCgp0ZW1wIDwtIGZ1bGxfam9pbihmdWxsX2pvaW4odGVtcC51cCwgdGVtcC5ubywgYnkgPSBjKCJ0YXJnZXQiKSksIHRlbXAuZG93biwgYnkgPSBjKCJ0YXJnZXQiKSkgJT4lIG11dGF0ZV9hbGwofnJlcGxhY2VfbmEoLiwgMSkpCgpkYXRhIDwtIGFzLm1hdHJpeCh0ZW1wWzI6NF0pCnJvd25hbWVzKGRhdGEpIDwtIHRlbXAkdGFyZ2V0CgpsaWJyYXJ5KGNpcmNsaXplKQpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYyhtaW4oZGF0YSksIG1heChkYXRhKSksIGMoIndoaXRlIiwgInJlZCIpKQoKCiNmdml6X25iY2x1c3QoZGF0YSwga21lYW5zLCBtZXRob2QgPSAid3NzIikKCiMgcCA8LSBIZWF0bWFwKAojICAgZGF0YSwKIyAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsICAgICAgICAgICAgICAgICAgICMgTmFtZSBvZiB0aGUgaGVhdG1hcCBsZWdlbmQKIyAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiMgICByb3dfa20gPSAxMCwgICAgICAgICAgICAgICAgICAgICAgICAgIyBEZWZpbmUgdGhlIG51bWJlciBvZiBrLW1lYW5zIGNsdXN0ZXJzIGZvciByb3dzIChhZGp1c3QgYXMgbmVlZGVkKQojICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAojICAgY29sID0gY29sX2Z1biwKIyAgIGJvcmRlciA9IFRSVUUKIyApCiMgCiMgZmlsZU5hbWUgPC0gcGFzdGUwKCJhbmNob3JMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX2FsbExvb3BzX2V4dHJlbWVfYWxsQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKIyBoZWlnaHQgPC0gNwojIHdpZHRoIDwtIDMuNQojIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCiMgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKIyBwcmludChwKQojIGRldi5vZmYoKQoKCgoKIyMjIFZpc3VhbGl6aW5nIHAtdmFsdWUgYW5kIE9SCmFscGhhIDwtIDAuMDUKIyB0Yi51cCA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3VwX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSkgJT4lCiMgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAojICAgICAgICAgICAgICAgICBxVmFsdWVMb2cgPSAtbG9nMihxVmFsdWUpLAojICAgICAgICAgICAgICAgICBncm91cCA9ICJVUCIpICU+JQojICAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKIyAgIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKIyB0Yi5ubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX25vX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSkgJT4lCiMgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAojICAgICAgICAgICAgICAgICBxVmFsdWVMb2cgPSAtbG9nMihxVmFsdWUpLAojICAgICAgICAgICAgICAgICBncm91cCA9ICJOTyIpICU+JQojICAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKIyAgIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIudXBubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX3Vwbm9fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzEwKHFWYWx1ZSksCiAgICAgICAgICAgICAgICBncm91cCA9ICJVUC9OTyIpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKZndyaXRlKHRiLnVwbm8gJT4lIGRwbHlyOjpzZWxlY3QoYygyNCwgMTYsIDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDQsIDI1LCA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDcsIDgsIDksIDEwLCAxMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMiwgMTMsIDE0KSksIGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfdXBub19hbGxMb29wc19leHRyZW1lX2F0YWNfcHViLnRzdiIpLCBzZXAgPSAiXHQiKQp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfZG93bl9hbGxMb29wc19leHRyZW1lX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSksCiAgICAgICAgICAgICAgICBxVmFsdWVMb2cgPSAtbG9nMTAocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIkRPV04iKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCmZ3cml0ZSh0Yi5kb3duICU+JSBkcGx5cjo6c2VsZWN0KGMoMjQsIDE2LCAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA0LCAyNSwgNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3LCA4LCA5LCAxMCwgMTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTIsIDEzLCAxNCkpLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX2Rvd25fYWxsTG9vcHNfZXh0cmVtZV9hdGFjX3B1Yi50c3YiKSwgc2VwID0gIlx0IikKCiMgdGVtcC51cCA8LSB0Yi51cCAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKIyB0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLnVwbm8gPC0gdGIudXBubyAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKdGVtcC5kb3duIDwtIHRiLmRvd24gJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8sIHFWYWx1ZUxvZywgZ3JvdXApCgp0ZW1wIDwtIGJpbmRfcm93cyh0ZW1wLnVwbm8sIHRlbXAuZG93bikKIyAKIyBvcmRlciA8LSBjKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJVUC9OTyIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCwgCiMgICAgICAgICAgICAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiRE9XTiIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCkKIyB0ZW1wJHRhcmdldCA8LSBmYWN0b3IodGVtcCR0YXJnZXQsIGxldmVscyA9IHJldihvcmRlcikpCnRlbXAkZ3JvdXAgPC0gZmFjdG9yKHRlbXAkZ3JvdXAsIGxldmVscyA9IGMoIlVQL05PIiwgIkRPV04iKSkKCgp0YXJnZXRMaXN0IDwtIGMoIlBPTFIyQSIsICJDVFI5IiwKICAgICAgICAgICAgICAgICJBRkY0IiwgIkVMTDIiLAogICAgICAgICAgICAgICAgIk1FRDEiLCAiTUVEMTIiLAogICAgICAgICAgICAgICAgIlRCUCIsICJUQUYxIiwgIlRBRjMiLAogICAgICAgICAgICAgICAgIkVTUlJCIiwgIktMRjQiLCAiTkFOT0ciLCAiUE9VNUYxIiwgIlNPWDIiLCAiU1RBVDMiLCAiRTJGMSIsICJZWTEiLAogICAgICAgICAgICAgICAgIkVQMzAwIiwgIkRQWTMwIiwgIkVaSDIiLCAiS0RNMkIiLCAiS0RCNEIiLCAiS0RNNEMiLCAiS0RNNkIiLCAiUkJCUDUiLAogICAgICAgICAgICAgICAgIlJBRDIxIiwgIlNNQzFBIiwgIlNNQzMiLCAiQ1RDRiIsCiAgICAgICAgICAgICAgICAiSkFSSUQyIiwgIlNVWjEyIgopCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcih0YXJnZXQgJWluJSB0YXJnZXRMaXN0KQoKdGVtcCR0YXJnZXQgPC0gZmFjdG9yKHRlbXAkdGFyZ2V0LCBsZXZlbHMgPSByZXYodGFyZ2V0TGlzdCkpCiMgTUFYIHFWYWx1ZUxvZyB0byA1MApxVmFsdWVMb2dNYXggPC0gNTAKdGVtcDIgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShxVmFsdWVMb2cgPSBtaW4ocVZhbHVlTG9nLCBxVmFsdWVMb2dNYXgpKQpwIDwtIGdncGxvdCh0ZW1wMiwgYWVzKHggPSBncm91cCwgeSA9IHRhcmdldCwgZmlsbCA9IG9kZHNSYXRpbywgc2l6ZSA9IHFWYWx1ZUxvZykpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsICAgICAgICAjIEVuc3VyZXMgYSBwb2ludCB3aXRoIGFuIG91dGxpbmUKICAgICAgICAgICAgIHN0cm9rZSA9IDAuNSpwdFRvTU0gICAgICAjIExpbmUgd2lkdGggZm9yIHRoZSBib3JkZXIKICApICsgdGhlbWVfYncoKSArIAogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMC41LCAyKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMSwgMyksCiAgICAgICAgICAgICAgICAgICAgICBvb2IgPSBzY2FsZXM6OnNxdWlzaCwgIyBEZWZpbmUgZ3JhZGllbnQgY29sb3JzCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKAogICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IDEuNS81LjA4LCAgIyBBZGp1c3Qgd2lkdGggb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICBiYXJoZWlnaHQgPSAxNS81LjA4ICAgIyBBZGp1c3QgaGVpZ2h0IG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICkKICApICsgCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImFuY2hvckxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfYWxsTG9vcHNfZXh0cmVtZV9PUl9xVmFsdWVfYWxsQW5jaG9yQmFja2dyb3VuZF9hdGFjX29yZGVyZWQiKQp3aWR0aCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDIuNSkqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKCmBgYAoKIyMjIGRUQUcsIG9ic2V4cAoKIyMjIyMgLSBMaW1pdGVkIHRvIEFUQUMtc2VxIHNpZ25hbCwgYWxsIGxvb3AgYmFja2dyb3VwCmBgYHtyfQphdGFjIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiR1NNMzEwNjI1N19BVEFDX0VTQ18xLmJlZCIpKSAlPiUgZHBseXI6OnNlbGVjdChWMSwgVjIsIFYzKQpjb2xuYW1lcyhhdGFjKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKYXRhYy5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoYXRhYykKCiMgTE9BRElORyBMT09QUwojIyMgSW1wb3J0aW5nIGRpZmZlcmVudGlhbCByZWd1bGF0b3J5IGxvb3BzICYgZXh0cmFjdCBhbmNob3IKbG9vcC5hbGwgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5LnRzdiIpKQphbmNob3IuYWxsIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuYWxsKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5hbGwsIGF0YWMuZ3IpCmFuY2hvci5hbGwgPC0gcGludGVyc2VjdChhbmNob3IuYWxsW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9sb2dPRV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC41LmJlZHBlIikpCmFuY2hvci51cCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci51cCwgYXRhYy5ncikKYW5jaG9yLnVwIDwtIHBpbnRlcnNlY3QoYW5jaG9yLnVwW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9sb2dPRV9hbGxfZFRBR3ZzRE1TT19OT19kaWZmMC41LmJlZHBlIikpCmFuY2hvci5ubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLm5vKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5ubywgYXRhYy5ncikKYW5jaG9yLm5vIDwtIHBpbnRlcnNlY3QoYW5jaG9yLm5vW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9sb2dPRV9hbGxfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjUuYmVkcGUiKSkKYW5jaG9yLmRvd24gPC0gKGV4dHJhY3RBbmNob3IobG9vcC5kb3duKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5kb3duLCBhdGFjLmdyKQphbmNob3IuZG93biA8LSBwaW50ZXJzZWN0KGFuY2hvci5kb3duW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKYGBgCgoKYGBge3J9CiMgUlVOTklORyBMT0xBCmxvbGFEaXIgPC0gaGVyZSgiLi4vLi4vcmVzdWx0L2xvbGEiKQpkaXIuY3JlYXRlKGxvbGFEaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQoKIyBVUApyZXN1bHQgPSBydW5MT0xBKGFuY2hvci51cCwgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fbG9nT0VfZGlmZjAuNV91cF9hbGxMb29wc19hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyBOTwpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5ubywgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fbG9nT0VfZGlmZjAuNV9ub19hbGxMb29wc19hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyBET1dOCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmRvd24sIGFuY2hvci5hbGwsIGxvbGFEQikKdGIgPSBhc190aWJibGUocmVzdWx0KQpmd3JpdGUodGIsIGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2xvZ09FX2RpZmYwLjVfZG93bl9hbGxMb29wc19hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKCgojIyMgSEVBVE1BUAphbHBoYSA8LSAwLjA1CnRiLnVwIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2xvZ09FX2RpZmYwLjVfdXBfYWxsTG9vcHNfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5ubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X25vX2FsbExvb3BzX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuZG93biA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X2Rvd25fYWxsTG9vcHNfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQoKdGVtcC51cCA8LSB0Yi51cCAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKY29sbmFtZXModGVtcC51cCkgPC0gYygidGFyZ2V0IiwgIk9SX3VwIikKdGVtcC5ubyA8LSB0Yi5ubyAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKY29sbmFtZXModGVtcC5ubykgPC0gYygidGFyZ2V0IiwgIk9SX25vIikKdGVtcC5kb3duIDwtIHRiLmRvd24gJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8pCmNvbG5hbWVzKHRlbXAuZG93bikgPC0gYygidGFyZ2V0IiwgIk9SX2Rvd24iKQoKCnRlbXAgPC0gZnVsbF9qb2luKGZ1bGxfam9pbih0ZW1wLnVwLCB0ZW1wLm5vLCBieSA9IGMoInRhcmdldCIpKSwgdGVtcC5kb3duLCBieSA9IGMoInRhcmdldCIpKSAlPiUgbXV0YXRlX2FsbCh+cmVwbGFjZV9uYSguLCAxKSkKCmRhdGEgPC0gYXMubWF0cml4KHRlbXBbMjo0XSkKcm93bmFtZXMoZGF0YSkgPC0gdGVtcCR0YXJnZXQKCmxpYnJhcnkoY2lyY2xpemUpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKG1pbihkYXRhKSwgbWF4KGRhdGEpKSwgYygid2hpdGUiLCAicmVkIikpCgoKI2Z2aXpfbmJjbHVzdChkYXRhLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQoKcCA8LSBIZWF0bWFwKAogIGRhdGEsCiAgbmFtZSA9ICJPZGRzIFJhdGlvIiwgICAgICAgICAgICAgICAgICAgIyBOYW1lIG9mIHRoZSBoZWF0bWFwIGxlZ2VuZAogIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiAgcm93X2ttID0gNCwgICAgICAgICAgICAgICAgICAgICAgICAjIERlZmluZSB0aGUgbnVtYmVyIG9mIGstbWVhbnMgY2x1c3RlcnMgZm9yIHJvd3MgKGFkanVzdCBhcyBuZWVkZWQpCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4sCiAgYm9yZGVyID0gVFJVRQopCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImFuY2hvckxPTEFfZFRBR192c19ETVNPX2xvZ09FX2RpZmYwLjVfYWxsTG9vcHNfYWxsQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKaGVpZ2h0IDwtIDcKd2lkdGggPC0gMy41CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKIyMjIyMjIyMjIyMjCiMgCiMgIyMjIFZpc3VhbGl6aW5nIHAtdmFsdWUgYW5kIE9SCiMgYWxwaGEgPC0gMC4wNQojIHRiLnVwIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2xvZ09FX2RpZmYwLjVfdXBfYWxsTG9vcHNfYXRhYy50c3YiKSkgJT4lCiMgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAojICAgICAgICAgICAgICAgICBxVmFsdWVMb2cgPSAtbG9nMihxVmFsdWUpLAojICAgICAgICAgICAgICAgICBncm91cCA9ICJVUCIpICU+JQojICAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKIyAgIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKIyB0Yi5ubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X25vX2FsbExvb3BzX2F0YWMudHN2IikpICU+JQojICAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKIyAgICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKIyAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiTk8iKSAlPiUKIyAgIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiMgICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiMgICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCiMgdGIuZG93biA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X2Rvd25fYWxsTG9vcHNfYXRhYy50c3YiKSkgJT4lCiMgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAojICAgICAgICAgICAgICAgICBxVmFsdWVMb2cgPSAtbG9nMihxVmFsdWUpLAojICAgICAgICAgICAgICAgICBncm91cCA9ICJET1dOIikgJT4lCiMgICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQojICAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQojICAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQojIAojIHRlbXAudXAgPC0gdGIudXAgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBvZGRzUmF0aW8sIHFWYWx1ZUxvZywgZ3JvdXApCiMgdGVtcC5ubyA8LSB0Yi5ubyAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKIyB0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKIyAKIyB0ZW1wIDwtIGJpbmRfcm93cyh0ZW1wLnVwLCB0ZW1wLmRvd24pCiMgCiMgb3JkZXIgPC0gYygodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiVVAiKSAlPiUgYXJyYW5nZShkZXNjKG9kZHNSYXRpbykpKSR0YXJnZXQsIAojICAgICAgICAgICAgKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIkRPV04iKSAlPiUgYXJyYW5nZShkZXNjKG9kZHNSYXRpbykpKSR0YXJnZXQpCiMgdGVtcCR0YXJnZXQgPC0gZmFjdG9yKHRlbXAkdGFyZ2V0LCBsZXZlbHMgPSByZXYob3JkZXIpKQojIHAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSB0YXJnZXQsIGNvbG9yID0gcVZhbHVlTG9nLCBzaXplID0gb2Rkc1JhdGlvKSkgKwojICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiMgICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgICsgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDEsIDMpKSArCiMgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKIyAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBheGlzIHRpdGxlIHNpemUgKGlmIG5vdCByZW1vdmVkKQojICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBsZWdlbmQgdGV4dCBzaXplCiMgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKIyAKIyBmaWxlTmFtZSA8LSBwYXN0ZTAoImFuY2hvckxPTEFfZFRBR192c19ETVNPX2xvZ09FX2RpZmYwLjVfYWxsTG9vcHNfT1JfYWxsQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKIyBoZWlnaHQgPC0zCiMgd2lkdGggPC0gMgojIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCiMgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKIyBwcmludChwKQojIGRldi5vZmYoKQoKCmBgYAoKIyMjIyMgLSBMaW1pdGluZyB0byBBVEFDLXNlcSBzaWduYWwsIHJlZyBsb29wIGJhY2tncm91bmQKYGBge3J9CmF0YWMgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJHU00zMTA2MjU3X0FUQUNfRVNDXzEuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKGF0YWMpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQphdGFjLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShhdGFjKQoKIyBMT0FESU5HIExPT1BTCiMjIyBJbXBvcnRpbmcgZGlmZmVyZW50aWFsIHJlZ3VsYXRvcnkgbG9vcHMgJiBleHRyYWN0IGFuY2hvcgpsb29wLmFsbCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkudHN2IikpICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJFLUUiKSkKYW5jaG9yLmFsbCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmFsbCkpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYWxsLCBhdGFjLmdyKQphbmNob3IuYWxsIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmFsbFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2xvZ09FX3BlLXBlX2RUQUd2c0RNU09fVVBfZGlmZjAuNS5iZWRwZSIpKQphbmNob3IudXAgPC0gKGV4dHJhY3RBbmNob3IobG9vcC51cCkpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IudXAsIGF0YWMuZ3IpCmFuY2hvci51cCA8LSBwaW50ZXJzZWN0KGFuY2hvci51cFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfbG9nT0VfcGUtcGVfZFRBR3ZzRE1TT19OT19kaWZmMC41LmJlZHBlIikpCmFuY2hvci5ubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLm5vKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5ubywgYXRhYy5ncikKYW5jaG9yLm5vIDwtIHBpbnRlcnNlY3QoYW5jaG9yLm5vW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9sb2dPRV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuNS5iZWRwZSIpKQphbmNob3IuZG93biA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmRvd24pKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmRvd24sIGF0YWMuZ3IpCmFuY2hvci5kb3duIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmRvd25bcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCgoKYGBgCgoKYGBge3J9CiMgUlVOTklORyBMT0xBCmxvbGFEaXIgPC0gaGVyZSgiLi4vLi4vcmVzdWx0L2xvbGEiKQpkaXIuY3JlYXRlKGxvbGFEaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQoKIyBVUApyZXN1bHQgPSBydW5MT0xBKGFuY2hvci51cCwgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fbG9nT0VfZGlmZjAuNV91cF9wZS1wZUxvb3BzX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIE5PCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLm5vLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X25vX3BlLXBlTG9vcHNfYXRhYy50c3YiKSwgc2VwID0gIlx0IikKCiMgRE9XTgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5kb3duLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X2Rvd25fcGUtcGVMb29wc19hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKCiMjIyBIRUFUTUFQCmFscGhhIDwtIDAuMDUKdGIudXAgPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fbG9nT0VfZGlmZjAuNV91cF9wZS1wZUxvb3BzX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fbG9nT0VfZGlmZjAuNV9ub19wZS1wZUxvb3BzX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuZG93biA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X2Rvd25fcGUtcGVMb29wc19hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLnVwKSA8LSBjKCJ0YXJnZXQiLCAiT1JfdXAiKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLm5vKSA8LSBjKCJ0YXJnZXQiLCAiT1Jfbm8iKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKY29sbmFtZXModGVtcC5kb3duKSA8LSBjKCJ0YXJnZXQiLCAiT1JfZG93biIpCgoKdGVtcCA8LSBmdWxsX2pvaW4oZnVsbF9qb2luKHRlbXAudXAsIHRlbXAubm8sIGJ5ID0gYygidGFyZ2V0IikpLCB0ZW1wLmRvd24sIGJ5ID0gYygidGFyZ2V0IikpICU+JSBtdXRhdGVfYWxsKH5yZXBsYWNlX25hKC4sIDEpKQoKZGF0YSA8LSBhcy5tYXRyaXgodGVtcFsyOjRdKQpyb3duYW1lcyhkYXRhKSA8LSB0ZW1wJHRhcmdldAoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMobWluKGRhdGEpLCBtYXgoZGF0YSkpLCBjKCJ3aGl0ZSIsICJyZWQiKSkKCgojZnZpel9uYmNsdXN0KGRhdGEsIGttZWFucywgbWV0aG9kID0gIndzcyIpCgpwIDwtIEhlYXRtYXAoCiAgZGF0YSwKICBuYW1lID0gIk9kZHMgUmF0aW8iLCAgICAgICAgICAgICAgICAgICAjIE5hbWUgb2YgdGhlIGhlYXRtYXAgbGVnZW5kCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICAgICAgICAgICAgIyBSZW1vdmUgY29sdW1uIGRlbmRyb2dyYW0KICByb3dfa20gPSA0LCAgICAgICAgICAgICAgICAgICAgICAgICAjIERlZmluZSB0aGUgbnVtYmVyIG9mIGstbWVhbnMgY2x1c3RlcnMgZm9yIHJvd3MgKGFkanVzdCBhcyBuZWVkZWQpCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4gICAgICAgICAgICAgICAgICAgICAgICMgVXNlIHRoZSByZWQgZ3JhZGllbnQgY29sb3Igc2NhbGUKKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJhbmNob3JMT0xBX2RUQUdfdnNfRE1TT19sb2dPRV9kaWZmMC41X3BlLXBlTG9vcHNfcmVnQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKaGVpZ2h0IDwtIDcKd2lkdGggPC0gMy41CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCiMjIyBWaXN1YWxpemluZyBwLXZhbHVlIGFuZCBPUgphbHBoYSA8LSAwLjA1CnRiLnVwIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfdXBfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKICAgICAgICAgICAgICAgIHFWYWx1ZUxvZyA9IC1sb2cyKHFWYWx1ZSksCiAgICAgICAgICAgICAgICBncm91cCA9ICJVUCIpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9ub19hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIk5PIikgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfZFRBR192c19ETVNPX2RpZmYwLjJfZG93bl9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIkRPV04iKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKCnRlbXAgPC0gYmluZF9yb3dzKHRlbXAudXAsIHRlbXAuZG93bikKCm9yZGVyIDwtIGMoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIlVQIikgJT4lIGFycmFuZ2UoZGVzYyhvZGRzUmF0aW8pKSkkdGFyZ2V0LCAKICAgICAgICAgICAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiRE9XTiIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCkKdGVtcCR0YXJnZXQgPC0gZmFjdG9yKHRlbXAkdGFyZ2V0LCBsZXZlbHMgPSByZXYob3JkZXIpKQpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGdyb3VwLCB5ID0gdGFyZ2V0LCBjb2xvciA9IHFWYWx1ZUxvZywgc2l6ZSA9IG9kZHNSYXRpbykpICsKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgYXhpcyB0aXRsZSBzaXplIChpZiBub3QgcmVtb3ZlZCkKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKCmZpbGVOYW1lIDwtIHBhc3RlMCgiYW5jaG9yTE9MQV9kVEFHX3ZzX0RNU09fZGlmZjAuMl9PUl9xVmFsdWVfcmVnQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKaGVpZ2h0IDwtMwp3aWR0aCA8LSAyCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgoKCgoKIyMjIDI0MTAxNSBUZXN0aW5nIG9uIHN1YnNldCBvZiBsb29wcwphbmNob3IuYzEgPC0gZXh0cmFjdEFuY2hvcihsb29wLmNsdXN0ZXIxKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmMxLCBhdGFjLmdyKQphbmNob3IuYzEgPC0gcGludGVyc2VjdChhbmNob3IuYzFbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmFuY2hvci5jMiA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjIpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzIsIGF0YWMuZ3IpCmFuY2hvci5jMiA8LSBwaW50ZXJzZWN0KGFuY2hvci5jMltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYW5jaG9yLmMzIDwtIGV4dHJhY3RBbmNob3IobG9vcC5jbHVzdGVyMykKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5jMywgYXRhYy5ncikKYW5jaG9yLmMzIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmMzW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgphbmNob3IuYzQgPC0gZXh0cmFjdEFuY2hvcihsb29wLmNsdXN0ZXI0KQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmM0LCBhdGFjLmdyKQphbmNob3IuYzQgPC0gcGludGVyc2VjdChhbmNob3IuYzRbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmFuY2hvci5jNSA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjUpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzUsIGF0YWMuZ3IpCmFuY2hvci5jNSA8LSBwaW50ZXJzZWN0KGFuY2hvci5jNVtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKYW5jaG9yLmM2IDwtIGV4dHJhY3RBbmNob3IobG9vcC5jbHVzdGVyNikKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5jNiwgYXRhYy5ncikKYW5jaG9yLmM2IDwtIHBpbnRlcnNlY3QoYW5jaG9yLmM2W3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgphbmNob3IuYzcgPC0gZXh0cmFjdEFuY2hvcihsb29wLmNsdXN0ZXI3KQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmM3LCBhdGFjLmdyKQphbmNob3IuYzcgPC0gcGludGVyc2VjdChhbmNob3IuYzdbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmFuY2hvci5jOCA8LSBleHRyYWN0QW5jaG9yKGxvb3AuY2x1c3RlcjgpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYzgsIGF0YWMuZ3IpCmFuY2hvci5jOCA8LSBwaW50ZXJzZWN0KGFuY2hvci5jOFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuYzEsIGFuY2hvci5hbGwsIGxvbGFEQikKdGIuYzEgPSBhc190aWJibGUocmVzdWx0KQoKcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuYzIsIGFuY2hvci5hbGwsIGxvbGFEQikKdGIuYzIgPSBhc190aWJibGUocmVzdWx0KQoKcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuYzMsIGFuY2hvci5hbGwsIGxvbGFEQikKdGIuYzMgPSBhc190aWJibGUocmVzdWx0KQoKcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuYzQsIGFuY2hvci5hbGwsIGxvbGFEQikKdGIuYzQgPSBhc190aWJibGUocmVzdWx0KQpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jNSwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jNSA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jNiwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jNiA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jNywgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jNyA9IGFzX3RpYmJsZShyZXN1bHQpCgpyZXN1bHQgPSBydW5MT0xBKGFuY2hvci5jOCwgYW5jaG9yLmFsbCwgbG9sYURCKQp0Yi5jOCA9IGFzX3RpYmJsZShyZXN1bHQpCgojIyMgSEVBVE1BUAphbHBoYSA8LSAwLjA1CnRiLmMxIDwtIHRiLmMxICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuYzIgPC0gdGIuYzIgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5jMyA8LSB0Yi5jMyAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCnRiLmM0IDwtIHRiLmM0ICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuYzUgPC0gdGIuYzUgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0Yi5jNiA8LSB0Yi5jNiAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JQogIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKCnRiLmM3IDwtIHRiLmM3ICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lCiAgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQoKdGIuYzggPC0gdGIuYzggJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLmMxIDwtIHRiLmMxICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmMxKSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzEiKQp0ZW1wLmMyIDwtIHRiLmMyICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmMyKSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzIiKQp0ZW1wLmMzIDwtIHRiLmMzICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmMzKSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzMiKQp0ZW1wLmM0IDwtIHRiLmM0ICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmM0KSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzQiKQp0ZW1wLmM1IDwtIHRiLmM1ICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmM1KSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzUiKQp0ZW1wLmM2IDwtIHRiLmM2ICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmM2KSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzYiKQp0ZW1wLmM3IDwtIHRiLmM3ICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmM3KSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzciKQp0ZW1wLmM4IDwtIHRiLmM4ICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLmM4KSA8LSBjKCJ0YXJnZXQiLCAiT1JfYzgiKQoKdGVtcCA8LSBmdWxsX2pvaW4odGVtcC5jMSwgdGVtcC5jMiwgYnkgPSAidGFyZ2V0IikgJT4lCiAgZnVsbF9qb2luKHRlbXAuYzMsIGJ5ID0gInRhcmdldCIpICU+JQogIGZ1bGxfam9pbih0ZW1wLmM0LCBieSA9ICJ0YXJnZXQiKSAlPiUKICBmdWxsX2pvaW4odGVtcC5jNSwgYnkgPSAidGFyZ2V0IikgJT4lCiAgZnVsbF9qb2luKHRlbXAuYzYsIGJ5ID0gInRhcmdldCIpICU+JQogIGZ1bGxfam9pbih0ZW1wLmM3LCBieSA9ICJ0YXJnZXQiKSAlPiUKICBmdWxsX2pvaW4odGVtcC5jOCwgYnkgPSAidGFyZ2V0IikgJT4lCiAgbXV0YXRlX2FsbCh+cmVwbGFjZV9uYSguLCAxKSkKCmRhdGEgPC0gdGVtcCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJ0YXJnZXQiKSAlPiUgYXMubWF0cml4KCkKCmxpYnJhcnkoY2lyY2xpemUpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDEsIG1heChkYXRhKSksIGMoIndoaXRlIiwgInJlZCIpKQoKCiNmdml6X25iY2x1c3QoZGF0YSwga21lYW5zLCBtZXRob2QgPSAid3NzIikKCnAgPC0gSGVhdG1hcCgKICBkYXRhLAogIG5hbWUgPSAiT2RkcyBSYXRpbyIsICAgICAgICAgICAgICAgICAgICMgTmFtZSBvZiB0aGUgaGVhdG1hcCBsZWdlbmQKICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwgICAgICAgICAgICAjIFJlbW92ZSBjb2x1bW4gZGVuZHJvZ3JhbQogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBjb2wgPSBjb2xfZnVuLAogIGJvcmRlciA9IFRSVUUKKQoKCiMgSW5pdGlhbGl6ZSBsaXN0cyB0byBzdG9yZSByZXN1bHRzCmFuY2hvcnMgPC0gbGlzdCgpCnRicyA8LSBsaXN0KCkKdGVtcHMgPC0gbGlzdCgpCgojIFByb2Nlc3MgY2x1c3RlcnMgYzEgdG8gYzgKZm9yIChpIGluIDE6NCkgewogICMgRXh0cmFjdCBhbmNob3IKICBsb29wX2NsdXN0ZXIgPC0gZ2V0KHBhc3RlMCgibG9vcC5jbHVzdGVyIiwgaSkpCiAgYW5jaG9yIDwtIGV4dHJhY3RBbmNob3IobG9vcF9jbHVzdGVyKQogIAogICMgRmluZCBvdmVybGFwcyBhbmQgaW50ZXJzZWN0CiAgb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvciwgYXRhYy5ncikKICBhbmNob3IgPC0gcGludGVyc2VjdChhbmNob3JbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKICAKICAjIFN0b3JlIGFuY2hvcgogIGFuY2hvcnNbW2ldXSA8LSBhbmNob3IKICAKICAjIFJ1biBMT0xBCiAgcmVzdWx0IDwtIHJ1bkxPTEEoYW5jaG9yLCBhbmNob3IuYWxsLCBsb2xhREIpCiAgdGIgPC0gYXNfdGliYmxlKHJlc3VsdCkKICAKICAjIEZpbHRlciBhbmQgc3VtbWFyaXplCiAgdGIgPC0gdGIgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICAgIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogICAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQogIAogICMgU3RvcmUgdGIKICB0YnNbW2ldXSA8LSB0YgogIAogICMgU2VsZWN0IGFuZCByZW5hbWUgb2Rkc1JhdGlvCiAgdGVtcCA8LSB0YiAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKICBjb2xuYW1lcyh0ZW1wKSA8LSBjKCJ0YXJnZXQiLCBwYXN0ZTAoIk9SX2MiLCBpKSkKICAKICAjIFN0b3JlIHRlbXAKICB0ZW1wc1tbaV1dIDwtIHRlbXAKfQoKIyBNZXJnZSBhbGwgdGVtcCB0YWJsZXMgaW50byBvbmUKdGVtcCA8LSBSZWR1Y2UoZnVuY3Rpb24oeCwgeSkgZnVsbF9qb2luKHgsIHksIGJ5ID0gInRhcmdldCIpLCB0ZW1wcykgJT4lCiAgbXV0YXRlX2FsbCh+cmVwbGFjZV9uYSguLCAxKSkKZGF0YSA8LSB0ZW1wICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoInRhcmdldCIpICU+JSBhcy5tYXRyaXgoKQoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMSwgbWF4KGRhdGEpKSwgYygid2hpdGUiLCAicmVkIikpCgoKI2Z2aXpfbmJjbHVzdChkYXRhLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQoKcCA8LSBIZWF0bWFwKAogIGRhdGEsCiAgbmFtZSA9ICJPZGRzIFJhdGlvIiwgICAgICAgICAgICAgICAgICAgIyBOYW1lIG9mIHRoZSBoZWF0bWFwIGxlZ2VuZAogIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4sCiAgYm9yZGVyID0gVFJVRQopCmBgYAoKCiMjIyBBNDg1CiMjIyMjIC0gTGltaXRlZCB0byBBVEFDLXNlcSBzaWduYWwsIGFsbCBsb29wIGJhY2tncm91cGQKYGBge3J9CmF0YWMgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJHU00zMTA2MjU3X0FUQUNfRVNDXzEuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKGF0YWMpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQphdGFjLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShhdGFjKQoKIyBMT0FESU5HIExPT1BTCiMjIyBJbXBvcnRpbmcgZGlmZmVyZW50aWFsIHJlZ3VsYXRvcnkgbG9vcHMgJiBleHRyYWN0IGFuY2hvcgpsb29wLmFsbCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkudHN2IikpCmFuY2hvci5hbGwgPC0gKGV4dHJhY3RBbmNob3IobG9vcC5hbGwpKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLmFsbCwgYXRhYy5ncikKYW5jaG9yLmFsbCA8LSBwaW50ZXJzZWN0KGFuY2hvci5hbGxbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9BNDg1dnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLnVwLCBhdGFjLmdyKQphbmNob3IudXAgPC0gcGludGVyc2VjdChhbmNob3IudXBbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5kb3duIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuZG93bikpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuZG93biwgYXRhYy5ncikKYW5jaG9yLmRvd24gPC0gcGludGVyc2VjdChhbmNob3IuZG93bltxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcE51bSA8LSBucm93KGxvb3AuZG93bikKCiMgU2VsZWN0aW5nIHNhbWUgbnVtYmVyIG9mIGV4dHJlbWUgbm8gbG9vcHMKbG9vcC5ubyA8LSBsb29wLmFsbCAlPiUgCiAgZHBseXI6Om11dGF0ZShhYnNEaWZmID0gYWJzKGRpZmZfQTQ4NV9ETVNPKSkgJT4lCiAgZHBseXI6OmZpbHRlcihhYnNEaWZmIDwgMC4yKSAlPiUKICBkcGx5cjo6YXJyYW5nZShhYnNEaWZmKSAlPiUgc2xpY2VfaGVhZChuID0gbG9vcE51bSkKYW5jaG9yLm5vIDwtIChleHRyYWN0QW5jaG9yKGxvb3Aubm8pKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLm5vLCBhdGFjLmdyKQphbmNob3Iubm8gPC0gcGludGVyc2VjdChhbmNob3Iubm9bcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKYGBgCgpgYGB7cn0KIyBSVU5OSU5HIExPTEEKbG9sYURpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQvbG9sYSIpCmRpci5jcmVhdGUobG9sYURpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgojIFVQCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLnVwLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX3VwX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSwgc2VwID0gIlx0IikKCiMgTk8KcmVzdWx0ID0gcnVuTE9MQShhbmNob3Iubm8sIGFuY2hvci5hbGwsIGxvbGFEQikKdGIgPSBhc190aWJibGUocmVzdWx0KQpmd3JpdGUodGIsIGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfbm9fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpLCBzZXAgPSAiXHQiKQoKIyBET1dOCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLmRvd24sIGFuY2hvci5hbGwsIGxvbGFEQikKdGIgPSBhc190aWJibGUocmVzdWx0KQpmd3JpdGUodGIsIGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfZG93bl9hbGxMb29wc19leHRyZW1lX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgoKCiMjIyBIRUFUTUFQCmFscGhhIDwtIDAuMDUKdGIudXAgPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl91cF9hbGxMb29wc19leHRyZW1lX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl9ub19hbGxMb29wc19leHRyZW1lX2F0YWMudHN2IikpICU+JQogIGRwbHlyOjptdXRhdGUodGFyZ2V0ID0gdG91cHBlcihhbnRpYm9keSkpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuZG93biA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX2Rvd25fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLnVwKSA8LSBjKCJ0YXJnZXQiLCAiT1JfdXAiKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLm5vKSA8LSBjKCJ0YXJnZXQiLCAiT1Jfbm8iKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKY29sbmFtZXModGVtcC5kb3duKSA8LSBjKCJ0YXJnZXQiLCAiT1JfZG93biIpCgoKdGVtcCA8LSBmdWxsX2pvaW4oZnVsbF9qb2luKHRlbXAudXAsIHRlbXAubm8sIGJ5ID0gYygidGFyZ2V0IikpLCB0ZW1wLmRvd24sIGJ5ID0gYygidGFyZ2V0IikpICU+JSBtdXRhdGVfYWxsKH5yZXBsYWNlX25hKC4sIDEpKQoKZGF0YSA8LSBhcy5tYXRyaXgodGVtcFsyOjRdKQpyb3duYW1lcyhkYXRhKSA8LSB0ZW1wJHRhcmdldAoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMobWluKGRhdGEpLCBtYXgoZGF0YSkpLCBjKCJ3aGl0ZSIsICJyZWQiKSkKCgojZnZpel9uYmNsdXN0KGRhdGEsIGttZWFucywgbWV0aG9kID0gIndzcyIpCgpwIDwtIEhlYXRtYXAoCiAgZGF0YSwKICBuYW1lID0gIk9kZHMgUmF0aW8iLCAgICAgICAgICAgICAgICAgICAjIE5hbWUgb2YgdGhlIGhlYXRtYXAgbGVnZW5kCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICAgICAgICAgICAgIyBSZW1vdmUgY29sdW1uIGRlbmRyb2dyYW0KICByb3dfa20gPSA1LCAgICAgICAgICAgICAgICAgICAgICAgICAjIERlZmluZSB0aGUgbnVtYmVyIG9mIGstbWVhbnMgY2x1c3RlcnMgZm9yIHJvd3MgKGFkanVzdCBhcyBuZWVkZWQpCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4sCiAgYm9yZGVyID0gVFJVRQopCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImFuY2hvckxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfYWxsTG9vcHNfZXh0cmVtZV9yZWdBbmNob3JCYWNrZ3JvdW5kX2F0YWMiKQpoZWlnaHQgPC0gNwp3aWR0aCA8LSAzLjUKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKCiMjIyBWaXN1YWxpemluZyBwLXZhbHVlIGFuZCBPUgphbHBoYSA8LSAwLjA1CnRiLnVwIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfdXBfYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIlVQIikgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5ubyA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX25vX2FsbExvb3BzX2V4dHJlbWVfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKICAgICAgICAgICAgICAgIHFWYWx1ZUxvZyA9IC1sb2cyKHFWYWx1ZSksCiAgICAgICAgICAgICAgICBncm91cCA9ICJOTyIpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIuZG93biA8LSBmcmVhZChoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX2Rvd25fYWxsTG9vcHNfZXh0cmVtZV9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIkRPV04iKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKCnRlbXAgPC0gYmluZF9yb3dzKHRlbXAudXAsIHRlbXAuZG93bikKCm9yZGVyIDwtIHVuaXF1ZShjKCh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJVUCIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCwgCiAgICAgICAgICAgKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIkRPV04iKSAlPiUgYXJyYW5nZShkZXNjKG9kZHNSYXRpbykpKSR0YXJnZXQpKQp0ZW1wJHRhcmdldCA8LSBmYWN0b3IodGVtcCR0YXJnZXQsIGxldmVscyA9IHJldihvcmRlcikpCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSB0YXJnZXQsIGNvbG9yID0gcVZhbHVlTG9nLCBzaXplID0gb2Rkc1JhdGlvKSkgKwogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSAgKyAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMSwgMykpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgYXhpcyB0aXRsZSBzaXplIChpZiBub3QgcmVtb3ZlZCkKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKCmZpbGVOYW1lIDwtIHBhc3RlMCgiYW5jaG9yTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl9hbGxMb29wc19leHRyZW1lX09SX3FWYWx1ZV9yZWdBbmNob3JCYWNrZ3JvdW5kX2F0YWMiKQpoZWlnaHQgPC0zCndpZHRoIDwtIDIKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKYGBgCgojIyMjIyAtIExpbWl0ZWQgdG8gQVRBQy1zZXEgc2lnbmFsLCByZWcgbG9vcCBiYWNrZ3JvdXVuZCAKYGBge3J9CmF0YWMgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJHU00zMTA2MjU3X0FUQUNfRVNDXzEuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKGF0YWMpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQphdGFjLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShhdGFjKQoKIyBMT0FESU5HIExPT1BTCiMjIyBJbXBvcnRpbmcgZGlmZmVyZW50aWFsIHJlZ3VsYXRvcnkgbG9vcHMgJiBleHRyYWN0IGFuY2hvcgpsb29wLmFsbCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkudHN2IikpICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJFLUUiKSkKYW5jaG9yLmFsbCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmFsbCkpCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuYWxsLCBhdGFjLmdyKQphbmNob3IuYWxsIDwtIHBpbnRlcnNlY3QoYW5jaG9yLmFsbFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci51cCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci51cCwgYXRhYy5ncikKYW5jaG9yLnVwIDwtIHBpbnRlcnNlY3QoYW5jaG9yLnVwW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLm5vIDwtIChleHRyYWN0QW5jaG9yKGxvb3Aubm8pKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLm5vLCBhdGFjLmdyKQphbmNob3Iubm8gPC0gcGludGVyc2VjdChhbmNob3Iubm9bcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLmRvd24gPC0gKGV4dHJhY3RBbmNob3IobG9vcC5kb3duKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5kb3duLCBhdGFjLmdyKQphbmNob3IuZG93biA8LSBwaW50ZXJzZWN0KGFuY2hvci5kb3duW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgoKYGBgCgpgYGB7cn0KIyBSVU5OSU5HIExPTEEKbG9sYURpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQvbG9sYSIpCmRpci5jcmVhdGUobG9sYURpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgojIFVQCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLnVwLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX3VwX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIE5PCnJlc3VsdCA9IHJ1bkxPTEEoYW5jaG9yLm5vLCBhbmNob3IuYWxsLCBsb2xhREIpCnRiID0gYXNfdGliYmxlKHJlc3VsdCkKZndyaXRlKHRiLCBoZXJlKGxvbGFEaXIsICJMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX25vX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgojIERPV04KcmVzdWx0ID0gcnVuTE9MQShhbmNob3IuZG93biwgYW5jaG9yLmFsbCwgbG9sYURCKQp0YiA9IGFzX3RpYmJsZShyZXN1bHQpCmZ3cml0ZSh0YiwgaGVyZShsb2xhRGlyLCAiTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl9kb3duX2F0YWMudHN2IiksIHNlcCA9ICJcdCIpCgoKCiMjIyBIRUFUTUFQCmFscGhhIDwtIDAuMDUKdGIudXAgPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl91cF9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCnRiLm5vIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfbm9fYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSkgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfZG93bl9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLnVwKSA8LSBjKCJ0YXJnZXQiLCAiT1JfdXAiKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvKQpjb2xuYW1lcyh0ZW1wLm5vKSA8LSBjKCJ0YXJnZXQiLCAiT1Jfbm8iKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKY29sbmFtZXModGVtcC5kb3duKSA8LSBjKCJ0YXJnZXQiLCAiT1JfZG93biIpCgoKdGVtcCA8LSBmdWxsX2pvaW4oZnVsbF9qb2luKHRlbXAudXAsIHRlbXAubm8sIGJ5ID0gYygidGFyZ2V0IikpLCB0ZW1wLmRvd24sIGJ5ID0gYygidGFyZ2V0IikpICU+JSBtdXRhdGVfYWxsKH5yZXBsYWNlX25hKC4sIDEpKQoKZGF0YSA8LSBhcy5tYXRyaXgodGVtcFsyOjRdKQpyb3duYW1lcyhkYXRhKSA8LSB0ZW1wJHRhcmdldAoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMobWluKGRhdGEpLCBtYXgoZGF0YSkpLCBjKCJ3aGl0ZSIsICJyZWQiKSkKCgpwIDwtIEhlYXRtYXAoCiAgZGF0YSwKICBuYW1lID0gIk9kZHMgUmF0aW8iLCAgICAgICAgICAgICAgICAgICAjIE5hbWUgb2YgdGhlIGhlYXRtYXAgbGVnZW5kCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICAgICAgICAgICAgIyBSZW1vdmUgY29sdW1uIGRlbmRyb2dyYW0KICByb3dfa20gPSA0LCAgICAgICAgICAgICAgICAgICAgICAgICAjIERlZmluZSB0aGUgbnVtYmVyIG9mIGstbWVhbnMgY2x1c3RlcnMgZm9yIHJvd3MgKGFkanVzdCBhcyBuZWVkZWQpCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4gICAgICAgICAgICAgICAgICAgICAgICMgVXNlIHRoZSByZWQgZ3JhZGllbnQgY29sb3Igc2NhbGUKKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJhbmNob3JMT0xBX0E0ODVfdnNfRE1TT19kaWZmMC4yX3JlZ0FuY2hvckJhY2tncm91bmRfYXRhYyIpCmhlaWdodCA8LSA3CndpZHRoIDwtIDMuNQpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCiMjIyBWaXN1YWxpemluZyBwLXZhbHVlIGFuZCBPUgphbHBoYSA8LSAwLjA1CnRiLnVwIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfdXBfYXRhYy50c3YiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSh0YXJnZXQgPSB0b3VwcGVyKGFudGlib2R5KSwKICAgICAgICAgICAgICAgIHFWYWx1ZUxvZyA9IC1sb2cyKHFWYWx1ZSksCiAgICAgICAgICAgICAgICBncm91cCA9ICJVUCIpICU+JQogIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihxVmFsdWUgPCBhbHBoYSkgJT4lIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogIHNsaWNlX21pbihtZWFuUm5rLCB3aXRoX3RpZXMgPSBGQUxTRSkKdGIubm8gPC0gZnJlYWQoaGVyZShsb2xhRGlyLCAiTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl9ub19hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIk5PIikgJT4lCiAgZmlsdGVyKHN0cl90b19sb3dlcihjZWxsVHlwZSkgPT0gImVtYnJ5b25pYyBzdGVtIGNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUgZHBseXI6Omdyb3VwX2J5KHRhcmdldCkgJT4lCiAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQp0Yi5kb3duIDwtIGZyZWFkKGhlcmUobG9sYURpciwgIkxPTEFfQTQ4NV92c19ETVNPX2RpZmYwLjJfZG93bl9hdGFjLnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpLAogICAgICAgICAgICAgICAgcVZhbHVlTG9nID0gLWxvZzIocVZhbHVlKSwKICAgICAgICAgICAgICAgIGdyb3VwID0gIkRPV04iKSAlPiUKICBmaWx0ZXIoc3RyX3RvX2xvd2VyKGNlbGxUeXBlKSA9PSAiZW1icnlvbmljIHN0ZW0gY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIocVZhbHVlIDwgYWxwaGEpICU+JSBkcGx5cjo6Z3JvdXBfYnkodGFyZ2V0KSAlPiUKICBzbGljZV9taW4obWVhblJuaywgd2l0aF90aWVzID0gRkFMU0UpCgp0ZW1wLnVwIDwtIHRiLnVwICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLm5vIDwtIHRiLm5vICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgb2Rkc1JhdGlvLCBxVmFsdWVMb2csIGdyb3VwKQp0ZW1wLmRvd24gPC0gdGIuZG93biAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbywgcVZhbHVlTG9nLCBncm91cCkKCnRlbXAgPC0gYmluZF9yb3dzKHRlbXAudXAsIHRlbXAuZG93bikKCm9yZGVyIDwtIGMoKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIlVQIikgJT4lIGFycmFuZ2UoZGVzYyhvZGRzUmF0aW8pKSkkdGFyZ2V0LCAKICAgICAgICAgICAodGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiRE9XTiIpICU+JSBhcnJhbmdlKGRlc2Mob2Rkc1JhdGlvKSkpJHRhcmdldCkKdGVtcCR0YXJnZXQgPC0gZmFjdG9yKHRlbXAkdGFyZ2V0LCBsZXZlbHMgPSByZXYob3JkZXIpKQpwIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGdyb3VwLCB5ID0gdGFyZ2V0LCBjb2xvciA9IHFWYWx1ZUxvZywgc2l6ZSA9IG9kZHNSYXRpbykpICsKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAgIyBTZXQgYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgYXhpcyB0aXRsZSBzaXplIChpZiBub3QgcmVtb3ZlZCkKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICMgU2V0IGxlZ2VuZCB0ZXh0IHNpemUKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSAKCmZpbGVOYW1lIDwtIHBhc3RlMCgiYW5jaG9yTE9MQV9BNDg1X3ZzX0RNU09fZGlmZjAuMl9PUl9xVmFsdWVfcmVnQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKaGVpZ2h0IDwtMwp3aWR0aCA8LSAyCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKCiMjIFsyLjIyXSBDb21wYXJpbmcgYWJzb2x1dGUgUk5BIGV4cHJlc3Npb24gbGV2ZWwgYWNyb3NzIGdyb3VwClRoZSBhaW0gaXMgdG8gc2VlIGlmIHRoZXJlIGlzIGEgdHJlbmQgaW4gUk5BIGV4cHJlc3Npb24gbGV2ZWwgYW1vbmcgZ3JvdXAgMSwgMiwgMywgNC4KSXQgd291bGQgYmUgbWFraW5nIGNvbXBhcmlzb24gYW1vbmcgZ2VuZXMuIEZvciB0aGlzLCBUUE0gc2hvdWxkIGJlIHVzZWQuCmBgYHtyfQojIyBJbXBvcnRpbmcgZ3JvdXBzCmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMi50c3YiKSkkZ2VuZQpncm91cDUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpKSRnZW5lCmdyb3VwOCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IikpJGdlbmUKCiMjIEltcG9ydGluZyBSTkEtc2VxIFRQTSBmb3IgRE1TTwp0cG0uc2VsZWN0ZWQgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJyZWFkQ291bnQuZmlsdGVyZWQuVFBNLmFsbC50c3YiKSkgJT4lIGRwbHlyOjpzZWxlY3QoMSwgMywgNCwgNSkKY29sbmFtZXModHBtLnNlbGVjdGVkKSA8LSBjKCJlbnNlbWJsIiwgInJlcDEiLCAicmVwMiIsICJyZXAzIikKCnRwbS5zZWxlY3RlZCA8LSB0cG0uc2VsZWN0ZWQgJT4lIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXAxLCAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICBpZmVsc2UoZW5zZW1ibCAlaW4lIGdyb3VwMiwgImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXA1LCAiZ3JvdXA1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlbnNlbWJsICVpbiUgZ3JvdXA4LCAiZ3JvdXA4IiwgTkEpKSkpKSAlPiUgCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKSAlPiUKICBkcGx5cjo6bXV0YXRlKGF2Z1RQTSA9IG1lYW4ocmVwMSwgcmVwMiwgcmVwMykpCgoKZ2dwbG90KHRwbS5zZWxlY3RlZCwgYWVzKHggPSBncm91cCwgeSA9IGF2Z1RQTSkpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArIAogIHNjYWxlX3lfbG9nMTAoKSArCiAgdGhlbWVfY2xhc3NpYygpCgoKCiAgcCA8LSBnZ3Bsb3QodGVtcC50YiwgYWVzKHggPSBncm91cCwgeSA9IHNjb3JlKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoeW1pbiwgeW1heCkpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSB5bWluICsgMSwgbGFiZWwgPSBwYXN0ZTAoInAxMjogIiwgY29udlB2YWx1ZShwMTIpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDE1OiAiLCBjb252UHZhbHVlKHAxNSksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTg6ICIsIGNvbnZQdmFsdWUocDE4KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAyNTogIiwgY29udlB2YWx1ZShwMjUpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDI4OiAiLCBjb252UHZhbHVlKHAyOCksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwNTg6ICIsY29udlB2YWx1ZSggcDU4KSwgIlxuIiksCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpCiAgCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uX3Njb3JlXyIsIG5vdGUpCiAgaGVpZ2h0IDwtIDMKICB3aWR0aCA8LSAzCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCmBgYAoKIyMgWzIuMjNdIENoZWNraW5nIEVhcmx5IGdlbmUgZnJvbSBCb2JiaWUKIyMjIyBkVEFHCmBgYHtyfQojIyBJbXBvcnRpbmcgZ3JvdXBzCmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2dyb3VwMi50c3YiKSkkZ2VuZQpncm91cDUgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA1LnRzdiIpKSRnZW5lCmdyb3VwOCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IikpJGdlbmUKCgojIyBJbXBvcnRpbmcgQm9iYmllIGdlbmUgY2xhc3NpZmljYXRpb24KZ2VuZUNsdXN0ZXIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJib2JiaWVfZ2VuZV9jbGFzc2lmaWNhdGlvbi5jc3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChnZW5lLCBlbnN0LCBDbHVzdGVyKQpjb2xuYW1lcyhnZW5lQ2x1c3RlcikgPC0gYygiZ2VuZSIsICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLCAiY2x1c3RlciIpCgoKIyMgQ29udmVydGluZyB0cmFuc2NyaXB0IElEIHRvIGdlbmUgSUQKaWRQYWlyX3RnIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLCAiZW5zZW1ibF9nZW5lX2lkIiksCiAgICAgICAgICAgICAgICAgZmlsdGVycyA9ICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLAogICAgICAgICAgICAgICAgIHZhbHVlcyA9IGdlbmVDbHVzdGVyJGVuc2VtYmxfdHJhbnNjcmlwdCwKICAgICAgICAgICAgICAgICBtYXJ0ID0gZW5zZW1ibC52MTAyKQpnZW5lQ2x1c3RlciA8LSBnZW5lQ2x1c3RlciAlPiUgZHBseXI6OmxlZnRfam9pbihpZFBhaXJfdGcsIGJ5ID0gYygiZW5zZW1ibF90cmFuc2NyaXB0X2lkIikpCgojIE1ha2luZyBkYXRhIGZvciBzdGFja2VkIGJhcnBsb3QKY291bnRHZW5lIDwtIGZ1bmN0aW9uKGdlbmVDbHVzdGVyLCBncm91cE5hbWUsIGNsdXN0ZXJOYW1lKXsKICBudW0gPC0gbnJvdyhnZW5lQ2x1c3RlciAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsX2dlbmVfaWQgJWluJSBncm91cE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlciAlaW4lIGNsdXN0ZXJOYW1lKSkKICByZXR1cm4obnVtKQp9CmNvdW50R2VuZUxpc3QgPC0gZnVuY3Rpb24oZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSl7CiAgbjEgPC0gY291bnRHZW5lKGdlbmVDbHVzdGVyLCBncm91cE5hbWUsICJFYXJseSIpCiAgbjIgPC0gY291bnRHZW5lKGdlbmVDbHVzdGVyLCBncm91cE5hbWUsICJNaWRkbGUiKQogIG4zIDwtY291bnRHZW5lKGdlbmVDbHVzdGVyLCBncm91cE5hbWUsICJMYXRlIikKICBuNCA8LSBjb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIlRyYW5zaWVudCIpCiAgcmV0dXJuKGMobjEsIG4yLCBuMywgbjQpKQp9Cgpncm91cCA8LSBjKHJlcCgiZ3JvdXAxIiwgNCksIHJlcCgiZ3JvdXAyIiwgNCksIHJlcCgiZ3JvdXAzIiwgNCksIHJlcCgiZ3JvdXA0IiwgNCkpCmNsdXN0ZXIgPC0gcmVwKGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpLCA0KQpjbHVzdGVyIDwtIGZhY3RvcihjbHVzdGVyLCBsZXZlbHMgPSBjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSkKdmFsdWUgPC0gYyhjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBncm91cDEpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdyb3VwMiksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ3JvdXA1KSwKICAgICAgICAgICBjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBncm91cDgpKQoKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKCgojIFBsb3R0aW5nCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKCiMgU3RhdGlzdGljYWwgYW5hbHlzaXMgCiMgU2ltaWxhciB0byB0aGUgQ2hpLVNxdWFyZSB0ZXN0LCBGaXNoZXLigJlzIEV4YWN0IFRlc3QgaXMgdXNlZCB3aGVuIHlvdSBoYXZlIHNtYWxsZXIgc2FtcGxlIHNpemVzIG9yIHdoZW4gdGhlIGV4cGVjdGVkIGZyZXF1ZW5jeSBpbiBhbnkgY2VsbCBvZiB0aGUgY29udGluZ2VuY3kgdGFibGUgaXMgYmVsb3cgNS4KdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwICVpbiUgYygiZ3JvdXAxIiwgImdyb3VwMiIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB4dGFicyh2YWx1ZSB+IGdyb3VwICsgY2x1c3RlciwgZGF0YSA9IHRlbXApCmZpc2hlcl9yZXN1bHQgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFLCBCID0gMTAwMDAwKQpmaXNoZXJfcmVzdWx0Cgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgJWluJSBjKCJncm91cDEiLCAiZ3JvdXAzIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHh0YWJzKHZhbHVlIH4gZ3JvdXAgKyBjbHVzdGVyLCBkYXRhID0gdGVtcCkKZmlzaGVyX3Jlc3VsdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxMDAwMDApCmZpc2hlcl9yZXN1bHQKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCAlaW4lIGMoImdyb3VwMSIsICJncm91cDQiKSkKY29udGluZ2VuY3lfdGFibGUgPC0geHRhYnModmFsdWUgfiBncm91cCArIGNsdXN0ZXIsIGRhdGEgPSB0ZW1wKQpmaXNoZXJfcmVzdWx0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlLCBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSwgQiA9IDEwMDAwMCkKZmlzaGVyX3Jlc3VsdAoKCiMjIyBQLU4KcmVzdWx0RGlyIDwtIGhlcmUoIi4uLy4uL3Jlc3VsdCIpCnRlbXAyIDwtIHJlYWRSRFMoaGVyZShyZXN1bHREaXIsICJnZW5lX2xvb3BfbGluay5yZHMiKSkKCnBuT3ZlcjggPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDgpKSRnZW5lCnBuT3ZlcjYgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsID49IDYsIHRvdGFsIDwgOCkpJGdlbmUKcG5PdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIodG90YWwgPj0gNCwgdG90YWwgPCA2KSkkZ2VuZQpwbk92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcih0b3RhbCA+PSAyLCB0b3RhbCA8IDQpKSRnZW5lCnBuT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKHRvdGFsIDwgMikpJGdlbmUKCmdyb3VwIDwtIGMocmVwKCJwbk92ZXI4IiwgNCksIHJlcCgicG5PdmVyNiIsIDQpLCByZXAoInBuT3ZlcjQiLCA0KSwgcmVwKCJwbk92ZXIyIiwgNCksIHJlcCgicG5PdmVyMCIsIDQpKQpjbHVzdGVyIDwtIHJlcChjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSwgNSkKY2x1c3RlciA8LSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gYygiRWFybHkiLCAiTWlkZGxlIiwgIkxhdGUiLCAiVHJhbnNpZW50IikpCnZhbHVlIDwtIGMoY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgcG5PdmVyOCksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgcG5PdmVyNiksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgcG5PdmVyNCksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgcG5PdmVyMiksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgcG5PdmVyMCkpCgpkYXRhIDwtIGRhdGEuZnJhbWUoZ3JvdXAsIGNsdXN0ZXIsIHZhbHVlKQojIFBsb3R0aW5nCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwICVpbiUgYygicG5PdmVyMiIsICJwbk92ZXI4IikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHh0YWJzKHZhbHVlIH4gZ3JvdXAgKyBjbHVzdGVyLCBkYXRhID0gdGVtcCkKZmlzaGVyX3Jlc3VsdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxMDAwMDApCmZpc2hlcl9yZXN1bHQKCiMjIyBQLVMKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAzLCBudW1fcHMgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMiwgbnVtX3BzIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDEsIG51bV9wcyA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA8IDEpKSRnZW5lCgpncm91cCA8LSBjKHJlcCgicHNPdmVyNCIsIDQpLCByZXAoInBzT3ZlcjMiLCA0KSwgcmVwKCJwc092ZXIyIiwgNCksIHJlcCgicHNPdmVyMSIsIDQpLCByZXAoInBzT3ZlcjAiLCA0KSkKY2x1c3RlciA8LSByZXAoYygiRWFybHkiLCAiTWlkZGxlIiwgIkxhdGUiLCAiVHJhbnNpZW50IiksIDUpCmNsdXN0ZXIgPC0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpKQp2YWx1ZSA8LSBjKGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBzT3ZlcjQpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBzT3ZlcjMpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBzT3ZlcjIpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBzT3ZlcjEpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBzT3ZlcjApKQoKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKIyBQbG90dGluZwpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwICVpbiUgYygicHNPdmVyMiIsICJwc092ZXI0IikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHh0YWJzKHZhbHVlIH4gZ3JvdXAgKyBjbHVzdGVyLCBkYXRhID0gdGVtcCkKZmlzaGVyX3Jlc3VsdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxMDAwMDApCmZpc2hlcl9yZXN1bHQKCiMjIyBQLUUKcGVPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDQpKSRnZW5lCnBlT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAzLCBudW1fcGUgPCA0KSkkZ2VuZQpwZU92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMiwgbnVtX3BlIDwgMykpJGdlbmUKcGVPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDEsIG51bV9wZSA8IDIpKSRnZW5lCnBlT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA8IDEpKSRnZW5lCgpncm91cCA8LSBjKHJlcCgicGVPdmVyNCIsIDQpLCByZXAoInBlT3ZlcjMiLCA0KSwgcmVwKCJwZU92ZXIyIiwgNCksIHJlcCgicGVPdmVyMSIsIDQpLCByZXAoInBlT3ZlcjAiLCA0KSkKY2x1c3RlciA8LSByZXAoYygiRWFybHkiLCAiTWlkZGxlIiwgIkxhdGUiLCAiVHJhbnNpZW50IiksIDUpCmNsdXN0ZXIgPC0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpKQp2YWx1ZSA8LSBjKGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBlT3ZlcjQpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBlT3ZlcjMpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBlT3ZlcjIpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBlT3ZlcjEpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBlT3ZlcjApKQoKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKIyBQbG90dGluZwpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKCiMjIyBQLVAKcHBPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDQpKSRnZW5lCnBwT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAzLCBudW1fcHAgPCA0KSkkZ2VuZQpwcE92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMiwgbnVtX3BwIDwgMykpJGdlbmUKcHBPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDEsIG51bV9wcCA8IDIpKSRnZW5lCnBwT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA8IDEpKSRnZW5lCgpncm91cCA8LSBjKHJlcCgicHBPdmVyNCIsIDQpLCByZXAoInBwT3ZlcjMiLCA0KSwgcmVwKCJwcE92ZXIyIiwgNCksIHJlcCgicHBPdmVyMSIsIDQpLCByZXAoInBwT3ZlcjAiLCA0KSkKY2x1c3RlciA8LSByZXAoYygiRWFybHkiLCAiTWlkZGxlIiwgIkxhdGUiLCAiVHJhbnNpZW50IiksIDUpCmNsdXN0ZXIgPC0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpKQp2YWx1ZSA8LSBjKGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBwT3ZlcjQpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBwT3ZlcjMpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBwT3ZlcjIpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBwT3ZlcjEpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIHBwT3ZlcjApKQpkYXRhIDwtIGRhdGEuZnJhbWUoZ3JvdXAsIGNsdXN0ZXIsIHZhbHVlKQojIFBsb3R0aW5nCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKYGBgCiMjIyMgQTQ4NQpgYGB7cn0KIyMgSW1wb3J0aW5nIGdyb3Vwcwpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDIudHN2IikpJGdlbmUKZ3JvdXAzIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwMy50c3YiKSkkZ2VuZQpncm91cDQgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA0LnRzdiIpKSRnZW5lCmdyb3VwNSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDUudHN2IikpJGdlbmUKZ3JvdXA2IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwNi50c3YiKSkkZ2VuZQpncm91cDcgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9BNDg1X3ZzX0RNU09fUk5BX2xvb3BfZ3JvdXA3LnRzdiIpKSRnZW5lCmdyb3VwOCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X0E0ODVfdnNfRE1TT19STkFfbG9vcF9ncm91cDgudHN2IikpJGdlbmUKZ3JvdXA5IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfQTQ4NV92c19ETVNPX1JOQV9sb29wX2dyb3VwOS50c3YiKSkkZ2VuZQoKCiMjIEltcG9ydGluZyBCb2JiaWUgZ2VuZSBjbGFzc2lmaWNhdGlvbgpnZW5lQ2x1c3RlciA8LSBmcmVhZChoZXJlKHJlZkRpciwgImJvYmJpZV9nZW5lX2NsYXNzaWZpY2F0aW9uLmNzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdlbmUsIGVuc3QsIENsdXN0ZXIpCmNvbG5hbWVzKGdlbmVDbHVzdGVyKSA8LSBjKCJnZW5lIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJjbHVzdGVyIikKCgojIyBDb252ZXJ0aW5nIHRyYW5zY3JpcHQgSUQgdG8gZ2VuZSBJRAppZFBhaXJfdGcgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJlbnNlbWJsX2dlbmVfaWQiKSwKICAgICAgICAgICAgICAgICBmaWx0ZXJzID0gImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsCiAgICAgICAgICAgICAgICAgdmFsdWVzID0gZ2VuZUNsdXN0ZXIkZW5zZW1ibF90cmFuc2NyaXB0LAogICAgICAgICAgICAgICAgIG1hcnQgPSBlbnNlbWJsLnYxMDIpCmdlbmVDbHVzdGVyIDwtIGdlbmVDbHVzdGVyICU+JSBkcGx5cjo6bGVmdF9qb2luKGlkUGFpcl90ZywgYnkgPSBjKCJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiKSkKCiMgTWFraW5nIGRhdGEgZm9yIHN0YWNrZWQgYmFycGxvdApjb3VudEdlbmUgPC0gZnVuY3Rpb24oZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgY2x1c3Rlck5hbWUpewogIG51bSA8LSBucm93KGdlbmVDbHVzdGVyICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGdyb3VwTmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyICVpbiUgY2x1c3Rlck5hbWUpKQogIHJldHVybihudW0pCn0KY291bnRHZW5lTGlzdCA8LSBmdW5jdGlvbihnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lKXsKICBuMSA8LSBjb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIkVhcmx5IikKICBuMiA8LSBjb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIk1pZGRsZSIpCiAgbjMgPC1jb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIkxhdGUiKQogIG40IDwtIGNvdW50R2VuZShnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCAiVHJhbnNpZW50IikKICByZXR1cm4oYyhuMSwgbjIsIG4zLCBuNCkpCn0KCmdyb3VwIDwtIGMocmVwKCJncm91cDEiLCA0KSwgcmVwKCJncm91cDIiLCA0KSwgcmVwKCJncm91cDMiLCA0KSwKICAgICAgICAgICByZXAoImdyb3VwNCIsIDQpLCByZXAoImdyb3VwNSIsIDQpLCByZXAoImdyb3VwNiIsIDQpLAogICAgICAgICAgIHJlcCgiZ3JvdXA3IiwgNCksIHJlcCgiZ3JvdXA4IiwgNCksIHJlcCgiZ3JvdXA5IiwgNCkpCmNsdXN0ZXIgPC0gcmVwKGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpLCA5KQpjbHVzdGVyIDwtIGZhY3RvcihjbHVzdGVyLCBsZXZlbHMgPSBjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSkKdmFsdWUgPC0gYyhjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBncm91cDEpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdyb3VwMiksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ3JvdXAzKSwKICAgICAgICAgICBjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBncm91cDQpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdyb3VwNSksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ3JvdXA2KSwKICAgICAgICAgICBjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBncm91cDcpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdyb3VwOCksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ3JvdXA5KSkKCmRhdGEgPC0gZGF0YS5mcmFtZShncm91cCwgY2x1c3RlciwgdmFsdWUpCgoKIyBQbG90dGluZwpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKCgojIFN0YXRpc3RpY2FsIGFuYWx5c2lzIAojIFNpbWlsYXIgdG8gdGhlIENoaS1TcXVhcmUgdGVzdCwgRmlzaGVy4oCZcyBFeGFjdCBUZXN0IGlzIHVzZWQgd2hlbiB5b3UgaGF2ZSBzbWFsbGVyIHNhbXBsZSBzaXplcyBvciB3aGVuIHRoZSBleHBlY3RlZCBmcmVxdWVuY3kgaW4gYW55IGNlbGwgb2YgdGhlIGNvbnRpbmdlbmN5IHRhYmxlIGlzIGJlbG93IDUuCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCAlaW4lIGMoImdyb3VwMSIsICJncm91cDIiKSkKY29udGluZ2VuY3lfdGFibGUgPC0geHRhYnModmFsdWUgfiBncm91cCArIGNsdXN0ZXIsIGRhdGEgPSB0ZW1wKQpmaXNoZXJfcmVzdWx0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlLCBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSwgQiA9IDEwMDAwMCkKZmlzaGVyX3Jlc3VsdAoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwICVpbiUgYygiZ3JvdXAxIiwgImdyb3VwMyIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB4dGFicyh2YWx1ZSB+IGdyb3VwICsgY2x1c3RlciwgZGF0YSA9IHRlbXApCmZpc2hlcl9yZXN1bHQgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFLCBCID0gMTAwMDAwKQpmaXNoZXJfcmVzdWx0Cgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgJWluJSBjKCJncm91cDEiLCAiZ3JvdXA0IikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHh0YWJzKHZhbHVlIH4gZ3JvdXAgKyBjbHVzdGVyLCBkYXRhID0gdGVtcCkKZmlzaGVyX3Jlc3VsdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxMDAwMDApCmZpc2hlcl9yZXN1bHQKCgpgYGAKCiMjIFsyLjI0XSBDaGVja2luZyBib29rbWFya2luZwooMSkgQ2hlY2tpbmcgd2hldGhlciBzdWJzZXQgb2YgcmVndWxhdG9yeSBsb29wIGhhdmUgYm9va21hcmtpbmcKKDIpIENoZWNraW5nIHdoZXRoZXIgbG9vcHMgcmVsYXRlZCB0byBnZW5lcyBoYXZlIGJvb2ttYXJraW5nCkgzSzI3YWNfZWZmaWUKQVRBQ19lZmZpZQpUQlAKT2N0NF9lZmZpZSwgT2N0NF9kc2cKU294Ml9lZmZpZSwgU294Ml9kc2cKRXNycmJfZHNnCktsZjRfZWZmaWUKQ1RDRgojIyMjIyBGdW5jdGlvbnMKYGBge3J9CmV4dHJhY3RBbmNob3IgPC0gZnVuY3Rpb24obG9vcCl7CiAgYW5jaG9yMSA8LSBsb29wICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCiAgY29sbmFtZXMoYW5jaG9yMSkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgYW5jaG9yMiA8LSBsb29wICU+JSBkcGx5cjo6c2VsZWN0KGMoNCwgNSwgNikpCiAgY29sbmFtZXMoYW5jaG9yMikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgYW5jaG9ycyA8LSByZWR1Y2UobWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGJpbmRfcm93cyhhbmNob3IxLCBhbmNob3IyKSkpCiAgICByZXR1cm4oYW5jaG9ycykKfQoKcnVuRmlzaGVyRXhhY3QgPC0gZnVuY3Rpb24oaW50ZXJlc3QuZ3IsIGJhY2tncm91bmQuZ3IsIHF1ZXJ5LmdyKXsKICBvdmVybGFwc19pbnRlcmVzdCA8LSBjb3VudE92ZXJsYXBzKGludGVyZXN0LmdyLCBxdWVyeS5ncikKICBhIDwtIHN1bShvdmVybGFwc19pbnRlcmVzdCA+IDApCiAgdG90YWxfaW50ZXJlc3QgPC0gbGVuZ3RoKGludGVyZXN0LmdyKQogIGMgPC0gdG90YWxfaW50ZXJlc3QgLSBhCiAgCiAgb3ZlcmxhcHNfYmFja2dyb3VuZCA8LSBjb3VudE92ZXJsYXBzKGJhY2tncm91bmQuZ3IsIHF1ZXJ5LmdyKQogIGIgPC0gc3VtKG92ZXJsYXBzX2JhY2tncm91bmQgPiAwKQogIHRvdGFsX2JhY2tncm91bmQgPC0gbGVuZ3RoKGJhY2tncm91bmQuZ3IpCiAgZCA8LSB0b3RhbF9iYWNrZ3JvdW5kIC0gYgogIAogICMgQ29uc3RydWN0IGNvbnRpbmdlbmN5IHRhYmxlCiAgY29udGluZ2VuY3lfdGFibGUgPC0gbWF0cml4KGMoYSwgYywgYiwgZCksIG5yb3c9MiwgYnlyb3c9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltbmFtZXM9bGlzdCgiUmVnaW9uIiA9IGMoImludGVyZXN0LmdyIiwgImJhY2tncm91bmQuZ3IiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3ZlcmxhcCIgPSBjKCJZZXMiLCAiTm8iKSkpCiAgCiAgIyBQZXJmb3JtIEZpc2hlcidzIGV4YWN0IHRlc3QKICBmaXNoZXJfcmVzdWx0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQogIAogIHJldHVybihmaXNoZXJfcmVzdWx0KQp9CgpydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uIDwtIGZ1bmN0aW9uKGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldGFpbmVkLmdyLCBsb3N0LmdyKXsKICAjIFNFRURJTkcKICB0ZW1wIDwtIHJ1bkZpc2hlckV4YWN0KGxvb3AudXAuZ3IsIGJhY2tncm91bmQuZ3IsIHJldGFpbmVkLmdyKQogIHJlc3VsdC50YiA8LSB0aWJibGUoaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQIiksCiAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9yZXRhaW5lZCIpLAogICAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKICAKICAjIEFERElORyBST1dTCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLm5vLmdyLCBiYWNrZ3JvdW5kLmdyLCByZXRhaW5lZC5ncikKICByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICAgIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX05PIiksCiAgICAgICAgICAgIHRhcmdldCA9IHBhc3RlMCh0YXJnZXROYW1lLCAiX3JldGFpbmVkIiksCiAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKICAKICAjIEFERElORyBST1dTCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLmRvd24uZ3IsIGJhY2tncm91bmQuZ3IsIHJldGFpbmVkLmdyKQogIHJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogICAgYWRkX3JvdyhpbnRlcmVzdCA9IHBhc3RlMChpbnRlcmVzdE5hbWUsICJfRE9XTiIpLAogICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9yZXRhaW5lZCIpLAogICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCiAgCiAgIyBBRERJTkcgUk9XUwogIHRlbXAgPC0gcnVuRmlzaGVyRXhhY3QobG9vcC51cC5nciwgYmFja2dyb3VuZC5nciwgbG9zdC5ncikKICByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICAgIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQIiksCiAgICAgICAgICAgIHRhcmdldCA9IHBhc3RlMCh0YXJnZXROYW1lLCAiX2xvc3QiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQogIAogICMgQURESU5HIFJPV1MKICB0ZW1wIDwtIHJ1bkZpc2hlckV4YWN0KGxvb3Aubm8uZ3IsIGJhY2tncm91bmQuZ3IsIGxvc3QuZ3IpCiAgcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgICBhZGRfcm93KGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9OTyIpLAogICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9sb3N0IiksCiAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKICAKICAjIEFERElORyBST1dTCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLmRvd24uZ3IsIGJhY2tncm91bmQuZ3IsIGxvc3QuZ3IpCiAgcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgICBhZGRfcm93KGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9ET1dOIiksCiAgICAgICAgICAgIHRhcmdldCA9IHBhc3RlMCh0YXJnZXROYW1lLCAiX2xvc3QiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQogIAogIHJldHVybihyZXN1bHQudGIpCn0KCnJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25CaW5hcnkgPC0gZnVuY3Rpb24oaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXBuby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXRhaW5lZC5nciwgbG9zdC5ncil7CiAgIyBTRUVESU5HCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLnVwbm8uZ3IsIGJhY2tncm91bmQuZ3IsIHJldGFpbmVkLmdyKQogIHJlc3VsdC50YiA8LSB0aWJibGUoaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQL05PIiksCiAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9yZXRhaW5lZCIpLAogICAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKICAKCiAgIyBBRERJTkcgUk9XUwogIHRlbXAgPC0gcnVuRmlzaGVyRXhhY3QobG9vcC5kb3duLmdyLCBiYWNrZ3JvdW5kLmdyLCByZXRhaW5lZC5ncikKICByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICAgIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX0RPV04iKSwKICAgICAgICAgICAgdGFyZ2V0ID0gcGFzdGUwKHRhcmdldE5hbWUsICJfcmV0YWluZWQiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQogIAogICMgQURESU5HIFJPV1MKICB0ZW1wIDwtIHJ1bkZpc2hlckV4YWN0KGxvb3AudXBuby5nciwgYmFja2dyb3VuZC5nciwgbG9zdC5ncikKICByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICAgIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQL05PIiksCiAgICAgICAgICAgIHRhcmdldCA9IHBhc3RlMCh0YXJnZXROYW1lLCAiX2xvc3QiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQoKICAKICAjIEFERElORyBST1dTCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLmRvd24uZ3IsIGJhY2tncm91bmQuZ3IsIGxvc3QuZ3IpCiAgcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgICBhZGRfcm93KGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9ET1dOIiksCiAgICAgICAgICAgIHRhcmdldCA9IHBhc3RlMCh0YXJnZXROYW1lLCAiX2xvc3QiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQogIAogIHJldHVybihyZXN1bHQudGIpCn0KCnJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25SZXRhaW5lZCA8LSBmdW5jdGlvbihpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXRhaW5lZC5ncil7CiAgIyBTRUVESU5HCiAgdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLnVwLmdyLCBiYWNrZ3JvdW5kLmdyLCByZXRhaW5lZC5ncikKICByZXN1bHQudGIgPC0gdGliYmxlKGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9VUCIpLAogICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0ID0gcGFzdGUwKHRhcmdldE5hbWUsICJfcmV0YWluZWQiKSwKICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCiAgCiAgIyBBRERJTkcgUk9XUwogIHRlbXAgPC0gcnVuRmlzaGVyRXhhY3QobG9vcC5uby5nciwgYmFja2dyb3VuZC5nciwgcmV0YWluZWQuZ3IpCiAgcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgICBhZGRfcm93KGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9OTyIpLAogICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9yZXRhaW5lZCIpLAogICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCiAgCiAgIyBBRERJTkcgUk9XUwogIHRlbXAgPC0gcnVuRmlzaGVyRXhhY3QobG9vcC5kb3duLmdyLCBiYWNrZ3JvdW5kLmdyLCByZXRhaW5lZC5ncikKICByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICAgIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX0RPV04iKSwKICAgICAgICAgICAgdGFyZ2V0ID0gcGFzdGUwKHRhcmdldE5hbWUsICJfcmV0YWluZWQiKSwKICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQogIAoKICByZXR1cm4ocmVzdWx0LnRiKQp9CgpydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0IDwtIGZ1bmN0aW9uKHRhcmdldE5hbWUsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncil7CiAgIyBSRVRBSU5FRCBsb29wCiAgcmV0YWluZWQgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJURl9ib29rbWFya2luZyIsIHRhcmdldE5hbWUsICJhbV9hLmJlZCIpKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQogIGNvbG5hbWVzKHJldGFpbmVkKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICByZXRhaW5lZC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmV0YWluZWQpCiAgIyBMT1NUIGxvb3AKICBsb3N0IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVEZfYm9va21hcmtpbmciLCB0YXJnZXROYW1lLCAib2EuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCiAgY29sbmFtZXMobG9zdCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgbG9zdC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUobG9zdCkKICAKICByZXN1bHQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvbihpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXRhaW5lZC5nciwgbG9zdC5ncikKICAKICByZXR1cm4ocmVzdWx0KQp9CgpydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0QmluYXJ5IDwtIGZ1bmN0aW9uKHRhcmdldE5hbWUsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwbm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKXsKICAjIFJFVEFJTkVEIGxvb3AKICByZXRhaW5lZCA8LSBmcmVhZChoZXJlKHJlZkRpciwgIlRGX2Jvb2ttYXJraW5nIiwgdGFyZ2V0TmFtZSwgImFtX2EuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCiAgY29sbmFtZXMocmV0YWluZWQpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQogIHJldGFpbmVkLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShyZXRhaW5lZCkKICAjIExPU1QgbG9vcAogIGxvc3QgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJURl9ib29rbWFya2luZyIsIHRhcmdldE5hbWUsICJvYS5iZWQiKSkgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKICBjb2xuYW1lcyhsb3N0KSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICBsb3N0LmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShsb3N0KQogIAogIHJlc3VsdCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uQmluYXJ5KGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwbm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0YWluZWQuZ3IsIGxvc3QuZ3IpCiAgCiAgcmV0dXJuKHJlc3VsdCkKfQoKcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkIDwtIGZ1bmN0aW9uKHRhcmdldE5hbWUsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncil7CiAgIyBSRVRBSU5FRCBsb29wCiAgcmV0YWluZWQgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJURl9ib29rbWFya2luZyIsIHRhcmdldE5hbWUsICJhbV9hLmJlZCIpKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQogIGNvbG5hbWVzKHJldGFpbmVkKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICByZXRhaW5lZC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmV0YWluZWQpCiAgIyBMT1NUIGxvb3AKICByZXN1bHQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblJldGFpbmVkKGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldGFpbmVkLmdyKQogIAogIHJldHVybihyZXN1bHQpCn0KYGBgCgojIyMjIyBBbGwgbG9vcHMKYGBge3J9CiMjIyMgSW1wb3J0aW5nIGxvb3BzIG9mIGludGVyZXN0CmludGVyZXN0TmFtZSA8LSAiYWxsTG9vcCIKIyBCQUNLR1JPVU5EIGxvb3AKYmFja2dyb3VuZCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsLmJlZHBlIikpCmJhY2tncm91bmQuZ3IgPC0gKGV4dHJhY3RBbmNob3IoYmFja2dyb3VuZCkpCiMgVVAgbG9vcApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmxvb3AudXAuZ3IgPC0gKGV4dHJhY3RBbmNob3IobG9vcC51cCkpCiMgTk8gbG9vcApsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8uZ3IgPC0gKGV4dHJhY3RBbmNob3IobG9vcC5ubykpCiMgRE9XTiBsb29wCmxvb3BOdW0gPC0gbnJvdyhsb29wLm5vKQpsb29wLmFsbCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkudHN2IikpCmxvb3AuZG93biA8LSBsb29wLmFsbCAlPiUgZHBseXI6OmZpbHRlcihkaWZmX2RUQUdfRE1TTyA8IC0wLjIpICU+JSBkcGx5cjo6YXJyYW5nZShkaWZmX2RUQUdfRE1TTykgJT4lIHNsaWNlX2hlYWQobiA9IGxvb3BOdW0pCmxvb3AuZG93bi5nciA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmRvd24pKQoKIyMjIyBJbXBvcnRpbmcgbG9vcHMgb2YgdGFyZ2V0CnRlbXAxIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkFUQUNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAyIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkNUQ0YiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAzIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkVTUlJCX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiRVNSUkJfTkNCIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJFU1JSQl9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA2IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA3IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIktMRjRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA4IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk5BTk9HX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDkgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiTkFOT0dfcGZhIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTAgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiT0NUNF9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDExIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk9DVDRfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTIgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiT0NUNF9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxMyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJTTUMxIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDE1IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNPWDJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTYgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxNyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJUQlAiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCgoKCgpkYXRhIDwtIGJpbmRfcm93cyh0ZW1wMSwgdGVtcDIsIHRlbXAzLCB0ZW1wNCwgdGVtcDUsCiAgICAgICAgIHRlbXA2LCB0ZW1wNywgdGVtcDgsIHRlbXA5LCB0ZW1wMTAsCiAgICAgICAgIHRlbXAxMSwgdGVtcDEyLCB0ZW1wMTMsIHRlbXAxNCwgdGVtcDE1LCB0ZW1wMTYgLHRlbXAxNykKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQoKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDUpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3RpdGxlID0gIkludGVyZXN0IiwKICAgICAgICByb3dfdGl0bGUgPSAiVGFyZ2V0IiwKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoYXQgPSBjKDAsIDEsIDIsIDMsIDQsIDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkpCmBgYAojIyMjIyBBbGwgbG9vcHMgcmVmaW5lZApgYGB7cn0KCgojIyMjIEltcG9ydGluZyBsb29wcyBvZiB0YXJnZXQKdGVtcDEgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiQVRBQ19lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDIgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiQ1RDRiIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDMgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiRVNSUkJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJIM0syN2FjX2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJLTEY0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNiA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJOQU5PR19kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA3IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk9DVDRfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wOCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJTTUMxIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA5IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNPWDJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTAgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiVEJQIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQoKCgoKZGF0YSA8LSBiaW5kX3Jvd3ModGVtcDEsIHRlbXAyLCB0ZW1wMywgdGVtcDQsIHRlbXA1LAogICAgICAgICB0ZW1wNiwgdGVtcDcsIHRlbXA4LCB0ZW1wOSwgdGVtcDEwKQoKIyBWaXN1YWxpemF0aW9uCmxpYnJhcnkoY2lyY2xpemUpCgpoZWF0bWFwX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBvZGRzUmF0aW8pICU+JQpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gb2Rkc1JhdGlvKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpwdmFsdWVfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIHB2YWx1ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IHB2YWx1ZSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgMyksIAogICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCkhlYXRtYXAoYXMubWF0cml4KGhlYXRtYXBfZGF0YSksCiAgICAgICAgbmFtZSA9ICJPZGRzIFJhdGlvIiwKICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICMgQWRkIGFubm90YXRpb24gZm9yIHAtdmFsdWVzCiAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBmaWxsKSB7CiAgICAgICAgICBwdmFsIDwtIHB2YWx1ZV9kYXRhW2ksIGpdCiAgICAgICAgICBsYWJlbCA8LSBpZmVsc2UocHZhbCA+IDAuMDUsICJuLnMuIiwgc3ByaW50ZigiJS4yZSIsIHB2YWwpKQogICAgICAgICAgZ3JpZC50ZXh0KGxhYmVsLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSAxMCkpCiAgICAgICAgfSwKICAgICAgICAjIEN1c3RvbWl6ZSB0aGUgaGVhdG1hcCBsYXlvdXQKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSW50ZXJlc3QiLAogICAgICAgIHJvd190aXRsZSA9ICJUYXJnZXQiLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChhdCA9IGMoMCwgMSwgMiwgMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEiLCAiMiIsICIzIikpKQoKYGBgCgoKIyMjIyMgUmVnIGxvb3BzCmBgYHtyfQojIyMjIEltcG9ydGluZyBsb29wcyBvZiBpbnRlcmVzdAppbnRlcmVzdE5hbWUgPC0gInJlZ0xvb3AiCiMgQkFDS0dST1VORCBsb29wCmJhY2tncm91bmQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpCmJhY2tncm91bmQuZ3IgPC0gKGV4dHJhY3RBbmNob3IoYmFja2dyb3VuZCkpCiMgVVAgbG9vcApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKbG9vcC51cC5nciA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwKSkKIyBOTyBsb29wCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vLmdyIDwtIChleHRyYWN0QW5jaG9yKGxvb3Aubm8pKQojIFVQTk8gbG9vcApsb29wLnVwbm8gPC0gYmluZF9yb3dzKGxvb3AudXAsIGxvb3Aubm8pCmxvb3AudXBuby5nciA8LSBleHRyYWN0QW5jaG9yKGxvb3AudXBubykKIyBET1dOIGxvb3AKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQpsb29wLmRvd24uZ3IgPC0gKGV4dHJhY3RBbmNob3IobG9vcC5kb3duKSkKYGBgCiMjIyMjIyBGaWd1cmUgLSBIM0syN2FjIG9ubHkKYGBge3J9CnRhcmdldE5hbWUgPC0gIkgzSzI3YWNfZWZmaWUiCiMgUkVUQUlORUQgbG9vcApyZXRhaW5lZCA8LSBmcmVhZChoZXJlKHJlZkRpciwgIlRGX2Jvb2ttYXJraW5nIiwgdGFyZ2V0TmFtZSwgImFtX2EuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCmNvbG5hbWVzKHJldGFpbmVkKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKcmV0YWluZWQuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHJldGFpbmVkKQojIExPU1QgbG9vcApsb3N0IDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVEZfYm9va21hcmtpbmciLCB0YXJnZXROYW1lLCAib2EuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCmNvbG5hbWVzKGxvc3QpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQpsb3N0LmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShsb3N0KQoKCiMgU0VFRElORwp0ZW1wIDwtIHJ1bkZpc2hlckV4YWN0KGxvb3AudXBuby5nciwgYmFja2dyb3VuZC5nciwgcmV0YWluZWQuZ3IpCnJlc3VsdC50YiA8LSB0aWJibGUoaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQL05PIiksCiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0ID0gcGFzdGUwKHRhcmdldE5hbWUsICJfcmV0YWluZWQiKSwKICAgICAgICAgICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCiMgQURESU5HIFJPV1MKdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLmRvd24uZ3IsIGJhY2tncm91bmQuZ3IsIHJldGFpbmVkLmdyKQpyZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICBhZGRfcm93KGludGVyZXN0ID0gcGFzdGUwKGludGVyZXN0TmFtZSwgIl9ET1dOIiksCiAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9yZXRhaW5lZCIpLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCiMgQURESU5HIFJPV1MKdGVtcCA8LSBydW5GaXNoZXJFeGFjdChsb29wLnVwbm8uZ3IsIGJhY2tncm91bmQuZ3IsIGxvc3QuZ3IpCnJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogIGFkZF9yb3coaW50ZXJlc3QgPSBwYXN0ZTAoaW50ZXJlc3ROYW1lLCAiX1VQL05PIiksCiAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAodGFyZ2V0TmFtZSwgIl9sb3N0IiksCiAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQoKIyBBRERJTkcgUk9XUwp0ZW1wIDwtIHJ1bkZpc2hlckV4YWN0KGxvb3AuZG93bi5nciwgYmFja2dyb3VuZC5nciwgbG9zdC5ncikKcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgYWRkX3JvdyhpbnRlcmVzdCA9IHBhc3RlMChpbnRlcmVzdE5hbWUsICJfRE9XTiIpLAogICAgICAgICAgdGFyZ2V0ID0gcGFzdGUwKHRhcmdldE5hbWUsICJfbG9zdCIpLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCgpyZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JQogIG11dGF0ZShpbnRlcmVzdCA9IHJlY29kZShpbnRlcmVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZWdMb29wX1VQL05PIiA9ICJVUC9OTyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZWdMb29wX0RPV04iID0gIkRPV04iKSwKICAgICAgICAgdGFyZ2V0ID0gcmVjb2RlKHRhcmdldCwKICAgICAgICAgICAgICAgICAgICAgICAgICJIM0syN2FjX2VmZmllX3JldGFpbmVkIiA9ICJSZXRhaW5lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiSDNLMjdhY19lZmZpZV9sb3N0IiA9ICJMb3N0IikpCgpyZXN1bHQudGIkaW50ZXJlc3QgPC0gZmFjdG9yKHJlc3VsdC50YiRpbnRlcmVzdCwgbGV2ZWxzID0gYygiVVAvTk8iLCAiRE9XTiIpKQoKcCA8LSBnZ3Bsb3QocmVzdWx0LnRiLCBhZXMoeCA9IGludGVyZXN0LCB5ID0gdGFyZ2V0LCBzaXplID0gLWxvZzEwKHB2YWx1ZSksIGZpbGwgPSBvZGRzUmF0aW8pKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCAgICAgICAgIyBFbnN1cmVzIGEgcG9pbnQgd2l0aCBhbiBvdXRsaW5lCiAgICAgICAgICAgICBzdHJva2UgPSAwLjUqcHRUb01NICAgICAgIyBMaW5lIHdpZHRoIGZvciB0aGUgYm9yZGVyCiAgKSArIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDEsIDMpKSArICAjIFNldCBtaW4gYW5kIG1heCBwb2ludCBzaXplcyBoZXJlCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzID0gYygiIzQ4NTJBMCIsICJ3aGl0ZSIsICIjQ0IzMzNBIiksICAjIERlZmluZSBncmFkaWVudCBjb2xvcnMKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHNjYWxlczo6cmVzY2FsZShjKDAuNSwgMSwgMS41KSksIGxpbWl0cyA9IGMoMC41LCAxLjUpLCAKICAgICAgICAgICAgICAgICAgICAgICNsb3cgPSAid2hpdGUiLCBoaWdoID0gIiNDQjMzM0EiLAogICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMSwgMyksCiAgICAgICAgICAgICAgICAgICAgICBvb2IgPSBzY2FsZXM6OnNxdWlzaCwgIyBEZWZpbmUgZ3JhZGllbnQgY29sb3JzCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKAogICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IDEuNS81LjA4LCAgIyBBZGp1c3Qgd2lkdGggb2YgdGhlIGNvbG9yIGJhcgogICAgICAgICAgICAgICAgICAgICAgICBiYXJoZWlnaHQgPSAxNS81LjA4ICAgIyBBZGp1c3QgaGVpZ2h0IG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICkKICApICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiaGVhdG1hcF9IM0syN2FjX2Jvb2ttYXJraW5nX3JlZ19kb3RwbG90IikKd2lkdGggPC0gcGFuZWxTaXplKDEuNykqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjEpKm1tVG9JbmNoCiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKc3ZnbGl0ZShwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIiksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKICAKYGBgCiMjIyMjIyBGaWd1cmUgLSBhbGwgdGFyZ2V0cwpgYGB7cn0KIyMjIyBJbXBvcnRpbmcgbG9vcHMgb2YgdGFyZ2V0Cgp0ZW1wMSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0QmluYXJ5KCJFU1JSQl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cG5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDIgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldEJpbmFyeSgiSDNLMjdhY19lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwbm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0QmluYXJ5KCJLTEY0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXBuby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA0IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRCaW5hcnkoIk9DVDRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cG5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDUgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldEJpbmFyeSgiU09YMl9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwbm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQoKCmRhdGEgPC0gYmluZF9yb3dzKHRlbXAxLCB0ZW1wMiwgdGVtcDMsIHRlbXA0LCB0ZW1wNSkKCgoKcmVzdWx0LnRiIDwtIGRhdGEgJT4lCiAgbXV0YXRlKGludGVyZXN0ID0gcmVjb2RlKGludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlZ0xvb3BfVVAvTk8iID0gIlVQL05PIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlZ0xvb3BfRE9XTiIgPSAiRE9XTiIpLAogICAgICAgICB0YXJnZXQgPSByZWNvZGUodGFyZ2V0LAogICAgICAgICAgICAgICAgICAgICAgICAgIkgzSzI3YWNfZWZmaWVfcmV0YWluZWQiID0gIkgzSzI3YWNfcmV0YWluZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkgzSzI3YWNfZWZmaWVfbG9zdCIgPSAiSDNLMjdhY19sb3N0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICJFU1JSQl9kc2dfcmV0YWluZWQiID0gIkVTUlJCX3JldGFpbmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJFU1JSQl9kc2dfbG9zdCIgPSAiRVNSUkJfbG9zdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiS0xGNF9lZmZpZV9yZXRhaW5lZCIgPSAiS0xGNF9yZXRhaW5lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiS0xGNF9lZmZpZV9sb3N0IiA9ICJLTEY0X2xvc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgIk9DVDRfZWZmaWVfcmV0YWluZWQiID0gIk9DVDRfcmV0YWluZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIk9DVDRfZWZmaWVfbG9zdCIgPSAiT0NUNF9sb3N0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICJTT1gyX2VmZmllX3JldGFpbmVkIiA9ICJTT1gyX3JldGFpbmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJTT1gyX2VmZmllX2xvc3QiID0gIlNPWDJfbG9zdCIpKQoKcmVzdWx0LnRiJGludGVyZXN0IDwtIGZhY3RvcihyZXN1bHQudGIkaW50ZXJlc3QsIGxldmVscyA9IGMoIlVQL05PIiwgIkRPV04iKSkKcmVzdWx0LnRiJHRhcmdldCA8LSBmYWN0b3IocmVzdWx0LnRiJHRhcmdldCwgbGV2ZWxzID0gcmV2KGMoIkgzSzI3YWNfcmV0YWluZWQiLCAiSDNLMjdhY19sb3N0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRVNSUkJfcmV0YWluZWQiLCAiRVNSUkJfbG9zdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIktMRjRfcmV0YWluZWQiLCAiS0xGNF9sb3N0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT0NUNF9yZXRhaW5lZCIsICJPQ1Q0X2xvc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTT1gyX3JldGFpbmVkIiwiU09YMl9sb3N0IikpKQoKcCA8LSBnZ3Bsb3QocmVzdWx0LnRiLCBhZXMoeCA9IGludGVyZXN0LCB5ID0gdGFyZ2V0LCBzaXplID0gLWxvZzEwKHB2YWx1ZSksIGZpbGwgPSBvZGRzUmF0aW8pKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCAgICAgICAgIyBFbnN1cmVzIGEgcG9pbnQgd2l0aCBhbiBvdXRsaW5lCiAgICAgICAgICAgICBzdHJva2UgPSAxKnB0VG9NTSAgICAgICMgTGluZSB3aWR0aCBmb3IgdGhlIGJvcmRlcgogICkgKyB0aGVtZV9idygpICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCAzKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiM0ODUyQTAiLCAid2hpdGUiLCAiI0NCMzMzQSIpLCAgIyBEZWZpbmUgZ3JhZGllbnQgY29sb3JzCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoYygwLjUsIDEsIDEuNSkpLCBsaW1pdHMgPSBjKDAuNSwgMS41KSwgCiAgICAgICAgICAgICAgICAgICAgICAjbG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDEsIDMpLAogICAgICAgICAgICAgICAgICAgICAgb29iID0gc2NhbGVzOjpzcXVpc2gsICMgRGVmaW5lIGdyYWRpZW50IGNvbG9ycwogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICMgQWRqdXN0IGhlaWdodCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICApCiAgKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApCgpmaWxlTmFtZSA8LSBoZXJlKGZpZ0RpciwgImhlYXRtYXBfYWxsdGFyZ2V0X2Jvb2ttYXJraW5nX3JlZ19kb3RwbG90IikKd2lkdGggPC0gcGFuZWxTaXplKDIuMikqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgyKSptbVRvSW5jaAojIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojIHByaW50KHApCiMgZGV2Lm9mZigpCnN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCgoKCgoKCgpgYGAKIyMjIyMjIFJldGFpbmVkICYgTG9zdApgYGB7cn0KIyMjIyBJbXBvcnRpbmcgbG9vcHMgb2YgdGFyZ2V0CnRlbXAxIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkFUQUNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAyIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkNUQ0YiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAzIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkVTUlJCX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiRVNSUkJfTkNCIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJFU1JSQl9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA2IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA3IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIktMRjRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA4IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk5BTk9HX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDkgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiTkFOT0dfcGZhIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTAgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiT0NUNF9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDExIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk9DVDRfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTIgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiT0NUNF9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxMyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJTTUMxIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDE1IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNPWDJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTYgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxNyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJUQlAiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCgoKCgpkYXRhIDwtIGJpbmRfcm93cyh0ZW1wMSwgdGVtcDIsIHRlbXAzLCB0ZW1wNCwgdGVtcDUsCiAgICAgICAgIHRlbXA2LCB0ZW1wNywgdGVtcDgsIHRlbXA5LCB0ZW1wMTAsCiAgICAgICAgIHRlbXAxMSwgdGVtcDEyLCB0ZW1wMTMsIHRlbXAxNCwgdGVtcDE1LCB0ZW1wMTYgLHRlbXAxNykKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQoKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDUpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3RpdGxlID0gIkludGVyZXN0IiwKICAgICAgICByb3dfdGl0bGUgPSAiVGFyZ2V0IiwKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoYXQgPSBjKDAsIDEsIDIsIDMsIDQsIDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkpCgpgYGAKIyMjIyMjICBSZXRhaW5lZApgYGB7cn0KCiMjIyMgSW1wb3J0aW5nIGxvb3BzIG9mIHRhcmdldAp0ZW1wMSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIkFUQUNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAyIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiQ1RDRiIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDMgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJFU1JSQl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA0IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiRVNSUkJfTkNCIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIkVTUlJCX3BmYSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDYgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJIM0syN2FjX2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIktMRjRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA4IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiTkFOT0dfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wOSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIk5BTk9HX3BmYSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDEwIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiT0NUNF9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDExIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiT0NUNF9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxMiA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIk9DVDRfcGZhIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTMgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJTTUMxIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJTT1gyX2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTUgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJTT1gyX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDE2IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiU09YMl9wZmEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxNyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIlRCUCIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKCgoKCmRhdGEgPC0gYmluZF9yb3dzKHRlbXAxLCB0ZW1wMiwgdGVtcDMsIHRlbXA0LCB0ZW1wNSwKICAgICAgICAgdGVtcDYsIHRlbXA3LCB0ZW1wOCwgdGVtcDksIHRlbXAxMCwKICAgICAgICAgdGVtcDExLCB0ZW1wMTIsIHRlbXAxMywgdGVtcDE0LCB0ZW1wMTUsIHRlbXAxNiAsdGVtcDE3KQoKIyBWaXN1YWxpemF0aW9uCmxpYnJhcnkoY2lyY2xpemUpCgpoZWF0bWFwX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBvZGRzUmF0aW8pICU+JQpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gb2Rkc1JhdGlvKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpwdmFsdWVfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIHB2YWx1ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IHB2YWx1ZSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgMyksIAogICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCkhlYXRtYXAoYXMubWF0cml4KGhlYXRtYXBfZGF0YSksCiAgICAgICAgbmFtZSA9ICJPZGRzIFJhdGlvIiwKICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICMgQWRkIGFubm90YXRpb24gZm9yIHAtdmFsdWVzCiAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBmaWxsKSB7CiAgICAgICAgICBwdmFsIDwtIHB2YWx1ZV9kYXRhW2ksIGpdCiAgICAgICAgICBsYWJlbCA8LSBpZmVsc2UocHZhbCA+IDAuMDUsICJuLnMuIiwgc3ByaW50ZigiJS4yZSIsIHB2YWwpKQogICAgICAgICAgZ3JpZC50ZXh0KGxhYmVsLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSAxMCkpCiAgICAgICAgfSwKICAgICAgICAjIEN1c3RvbWl6ZSB0aGUgaGVhdG1hcCBsYXlvdXQKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSW50ZXJlc3QiLAogICAgICAgIHJvd190aXRsZSA9ICJUYXJnZXQiLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChhdCA9IGMoMCwgMSwgMiwgMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEiLCAiMiIsICIzIikpKQoKYGBgCgojIyMjIFJlZyByZWZpbmVkCiMjIyMjIyBSZXRhaW5lZCAmIExvc3QKYGBge3J9CgoKIyMjIyBJbXBvcnRpbmcgbG9vcHMgb2YgdGFyZ2V0CnRlbXAxIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkFUQUNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAyIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkNUQ0YiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAzIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkVTUlJCX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDQgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiSDNLMjdhY19lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDUgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiS0xGNF9lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDYgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiTkFOT0dfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJPQ1Q0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wOCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJTTUMxIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA5IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNPWDJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMTAgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiVEJQIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQoKCgoKZGF0YSA8LSBiaW5kX3Jvd3ModGVtcDEsIHRlbXAyLCB0ZW1wMywgdGVtcDQsIHRlbXA1LAogICAgICAgICB0ZW1wNiwgdGVtcDcsIHRlbXA4LCB0ZW1wOSwgdGVtcDEwKQoKIyBWaXN1YWxpemF0aW9uCmxpYnJhcnkoY2lyY2xpemUpCgpoZWF0bWFwX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBvZGRzUmF0aW8pICU+JQpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gb2Rkc1JhdGlvKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpwdmFsdWVfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIHB2YWx1ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IHB2YWx1ZSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgMyksIAogICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCkhlYXRtYXAoYXMubWF0cml4KGhlYXRtYXBfZGF0YSksCiAgICAgICAgbmFtZSA9ICJPZGRzIFJhdGlvIiwKICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICMgQWRkIGFubm90YXRpb24gZm9yIHAtdmFsdWVzCiAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBmaWxsKSB7CiAgICAgICAgICBwdmFsIDwtIHB2YWx1ZV9kYXRhW2ksIGpdCiAgICAgICAgICBsYWJlbCA8LSBpZmVsc2UocHZhbCA+IDAuMDUsICJuLnMuIiwgc3ByaW50ZigiJS4yZSIsIHB2YWwpKQogICAgICAgICAgZ3JpZC50ZXh0KGxhYmVsLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSAxMCkpCiAgICAgICAgfSwKICAgICAgICAjIEN1c3RvbWl6ZSB0aGUgaGVhdG1hcCBsYXlvdXQKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSW50ZXJlc3QiLAogICAgICAgIHJvd190aXRsZSA9ICJUYXJnZXQiLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChhdCA9IGMoMCwgMSwgMiwgMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEiLCAiMiIsICIzIikpKQoKCgpgYGAKIyMjIyMjIFJldGFpbmVkCmBgYHtyfQoKCiMjIyMgSW1wb3J0aW5nIGxvb3BzIG9mIHRhcmdldAp0ZW1wMSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIkFUQUNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAyIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiQ1RDRiIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDMgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJFU1JSQl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA0IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiSDNLMjdhY19lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDUgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJLTEY0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNiA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIk5BTk9HX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDcgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJPQ1Q0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wOCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0UmV0YWluZWQoIlNNQzEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDkgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldFJldGFpbmVkKCJTT1gyX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDEwIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXRSZXRhaW5lZCgiVEJQIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQoKCgoKZGF0YSA8LSBiaW5kX3Jvd3ModGVtcDEsIHRlbXAyLCB0ZW1wMywgdGVtcDQsIHRlbXA1LAogICAgICAgICB0ZW1wNiwgdGVtcDcsIHRlbXA4LCB0ZW1wOSwgdGVtcDEwKQoKIyBWaXN1YWxpemF0aW9uCmxpYnJhcnkoY2lyY2xpemUpCgpoZWF0bWFwX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBvZGRzUmF0aW8pICU+JQpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gb2Rkc1JhdGlvKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpwdmFsdWVfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIHB2YWx1ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IHB2YWx1ZSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgMyksIAogICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCkhlYXRtYXAoYXMubWF0cml4KGhlYXRtYXBfZGF0YSksCiAgICAgICAgbmFtZSA9ICJPZGRzIFJhdGlvIiwKICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICMgQWRkIGFubm90YXRpb24gZm9yIHAtdmFsdWVzCiAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBmaWxsKSB7CiAgICAgICAgICBwdmFsIDwtIHB2YWx1ZV9kYXRhW2ksIGpdCiAgICAgICAgICBsYWJlbCA8LSBpZmVsc2UocHZhbCA+IDAuMDUsICJuLnMuIiwgc3ByaW50ZigiJS4yZSIsIHB2YWwpKQogICAgICAgICAgZ3JpZC50ZXh0KGxhYmVsLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSAxMCkpCiAgICAgICAgfSwKICAgICAgICAjIEN1c3RvbWl6ZSB0aGUgaGVhdG1hcCBsYXlvdXQKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSW50ZXJlc3QiLAogICAgICAgIHJvd190aXRsZSA9ICJUYXJnZXQiLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChhdCA9IGMoMCwgMSwgMiwgMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEiLCAiMiIsICIzIikpKQoKCgpgYGAKIyMgWzIuMjQuMl0gQ2hlY2tpbmcgYm9va21hcmtpbmcgLSBBNDg1CiMjIyMgQWxsIGxvb3BzCmBgYHtyfQojIyMjIEltcG9ydGluZyBsb29wcyBvZiBpbnRlcmVzdAppbnRlcmVzdE5hbWUgPC0gImFsbExvb3AiCiMgQkFDS0dST1VORCBsb29wCmJhY2tncm91bmQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbC5iZWRwZSIpKQpiYWNrZ3JvdW5kLmdyIDwtIChleHRyYWN0QW5jaG9yKGJhY2tncm91bmQpKQojIFVQIGxvb3AKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLnVwLmdyIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQojIE5PIGxvb3AKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vLmdyIDwtIChleHRyYWN0QW5jaG9yKGxvb3Aubm8pKQojIERPV04gbG9vcApsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQpsb29wLmRvd24uZ3IgPC0gKGV4dHJhY3RBbmNob3IobG9vcC5kb3duKSkKYGBgCiMjIyMjIEFsbCBsb29wcyByZWZpbmVkCmBgYHtyfQoKCiMjIyMgSW1wb3J0aW5nIGxvb3BzIG9mIHRhcmdldAp0ZW1wMSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJBVEFDX2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMiA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJDVENGIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wMyA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJFU1JSQl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA0IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA1IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIktMRjRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA2IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk5BTk9HX2RzZyIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDcgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiT0NUNF9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA4IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNNQzEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDkgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxMCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJUQlAiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCgoKCgpkYXRhIDwtIGJpbmRfcm93cyh0ZW1wMSwgdGVtcDIsIHRlbXAzLCB0ZW1wNCwgdGVtcDUsCiAgICAgICAgIHRlbXA2LCB0ZW1wNywgdGVtcDgsIHRlbXA5LCB0ZW1wMTApCgojIFZpc3VhbGl6YXRpb24KbGlicmFyeShjaXJjbGl6ZSkKCmhlYXRtYXBfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIG9kZHNSYXRpbykgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBvZGRzUmF0aW8pICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCnB2YWx1ZV9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgcHZhbHVlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gcHZhbHVlKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYygwLCAxLCAzKSwgCiAgICAgICAgICAgICAgICAgICAgICBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQoKSGVhdG1hcChhcy5tYXRyaXgoaGVhdG1hcF9kYXRhKSwKICAgICAgICBuYW1lID0gIk9kZHMgUmF0aW8iLAogICAgICAgIGNvbCA9IGNvbF9mdW4sCiAgICAgICAgIyBBZGQgYW5ub3RhdGlvbiBmb3IgcC12YWx1ZXMKICAgICAgICBjZWxsX2Z1biA9IGZ1bmN0aW9uKGosIGksIHgsIHksIHdpZHRoLCBoZWlnaHQsIGZpbGwpIHsKICAgICAgICAgIHB2YWwgPC0gcHZhbHVlX2RhdGFbaSwgal0KICAgICAgICAgIGxhYmVsIDwtIGlmZWxzZShwdmFsID4gMC4wNSwgIm4ucy4iLCBzcHJpbnRmKCIlLjJlIiwgcHZhbCkpCiAgICAgICAgICBncmlkLnRleHQobGFiZWwsIHgsIHksIGdwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSkKICAgICAgICB9LAogICAgICAgICMgQ3VzdG9taXplIHRoZSBoZWF0bWFwIGxheW91dAogICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgIGNvbHVtbl90aXRsZSA9ICJJbnRlcmVzdCIsCiAgICAgICAgcm93X3RpdGxlID0gIlRhcmdldCIsCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGF0ID0gYygwLCAxLCAyLCAzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMSIsICIyIiwgIjMiKSkpCgpgYGAKIyMjIyBSZWcgbG9vcHMKYGBge3J9CiMjIyMgSW1wb3J0aW5nIGxvb3BzIG9mIGludGVyZXN0CmludGVyZXN0TmFtZSA8LSAicmVnTG9vcCIKIyBCQUNLR1JPVU5EIGxvb3AKYmFja2dyb3VuZCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkKYmFja2dyb3VuZC5nciA8LSAoZXh0cmFjdEFuY2hvcihiYWNrZ3JvdW5kKSkKIyBVUCBsb29wCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0E0ODV2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLnVwLmdyIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQojIE5PIGxvb3AKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8uZ3IgPC0gKGV4dHJhY3RBbmNob3IobG9vcC5ubykpCiMgRE9XTiBsb29wCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkKbG9vcC5kb3duLmdyIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuZG93bikpCgpmd3JpdGUoYXNfdGliYmxlKGxvb3AudXAuZ3IpICU+JSBkcGx5cjo6c2VsZWN0KHNlcW5hbWVzLCBzdGFydCwgZW5kKSwgaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0E0ODV2c0RNU09fVVBfZGlmZjAuMi5hbmNob3IuYmVkIiksIGNvbC5uYW1lcyA9IEZBTFNFLCBzZXAgPSAiXHQiKQpmd3JpdGUoYXNfdGliYmxlKGxvb3Aubm8uZ3IpICU+JSBkcGx5cjo6c2VsZWN0KHNlcW5hbWVzLCBzdGFydCwgZW5kKSwgaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0E0ODV2c0RNU09fTk9fZGlmZjAuMi5hbmNob3IuYmVkIiksIGNvbC5uYW1lcyA9IEZBTFNFLCBzZXAgPSAiXHQiKQpmd3JpdGUoYXNfdGliYmxlKGxvb3AuZG93bi5ncikgJT4lIGRwbHlyOjpzZWxlY3Qoc2VxbmFtZXMsIHN0YXJ0LCBlbmQpLCBoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19ET1dOX2RpZmYwLjIuYW5jaG9yLmJlZCIpLCBjb2wubmFtZXMgPSBGQUxTRSwgc2VwID0gIlx0IikKYGBgCiMjIyMjIFJldGFpbmVkICYgTG9zdApgYGB7cn0KCgojIyMjIEltcG9ydGluZyBsb29wcyBvZiB0YXJnZXQKdGVtcDEgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiQVRBQ19lZmZpZSIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDIgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiQ1RDRiIsIGludGVyZXN0TmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDMgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiRVNSUkJfZHNnIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJIM0syN2FjX2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNSA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJLTEY0X2VmZmllIiwgaW50ZXJlc3ROYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3AudXAuZ3IsIGxvb3Aubm8uZ3IsIGxvb3AuZG93bi5nciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLmdyKQp0ZW1wNiA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJOQU5PR19kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA3IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIk9DVDRfZWZmaWUiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXA4IDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIlNNQzEiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wLnVwLmdyLCBsb29wLm5vLmdyLCBsb29wLmRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC5ncikKdGVtcDkgPC0gcnVuRmlzaGVyRXhhY3RDb21iaW5hdGlvblRhcmdldCgiU09YMl9kc2ciLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCnRlbXAxMCA8LSBydW5GaXNoZXJFeGFjdENvbWJpbmF0aW9uVGFyZ2V0KCJUQlAiLCBpbnRlcmVzdE5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcC51cC5nciwgbG9vcC5uby5nciwgbG9vcC5kb3duLmdyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQuZ3IpCgoKCgpkYXRhIDwtIGJpbmRfcm93cyh0ZW1wMSwgdGVtcDIsIHRlbXAzLCB0ZW1wNCwgdGVtcDUsCiAgICAgICAgIHRlbXA2LCB0ZW1wNywgdGVtcDgsIHRlbXA5LCB0ZW1wMTApCgojIFZpc3VhbGl6YXRpb24KbGlicmFyeShjaXJjbGl6ZSkKCmhlYXRtYXBfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgaW50ZXJlc3QsIG9kZHNSYXRpbykgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBvZGRzUmF0aW8pICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCnB2YWx1ZV9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgcHZhbHVlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW50ZXJlc3QsIHZhbHVlc19mcm9tID0gcHZhbHVlKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYygwLCAxLCAzKSwgCiAgICAgICAgICAgICAgICAgICAgICBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQoKSGVhdG1hcChhcy5tYXRyaXgoaGVhdG1hcF9kYXRhKSwKICAgICAgICBuYW1lID0gIk9kZHMgUmF0aW8iLAogICAgICAgIGNvbCA9IGNvbF9mdW4sCiAgICAgICAgIyBBZGQgYW5ub3RhdGlvbiBmb3IgcC12YWx1ZXMKICAgICAgICBjZWxsX2Z1biA9IGZ1bmN0aW9uKGosIGksIHgsIHksIHdpZHRoLCBoZWlnaHQsIGZpbGwpIHsKICAgICAgICAgIHB2YWwgPC0gcHZhbHVlX2RhdGFbaSwgal0KICAgICAgICAgIGxhYmVsIDwtIGlmZWxzZShwdmFsID4gMC4wNSwgIm4ucy4iLCBzcHJpbnRmKCIlLjJlIiwgcHZhbCkpCiAgICAgICAgICBncmlkLnRleHQobGFiZWwsIHgsIHksIGdwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSkKICAgICAgICB9LAogICAgICAgICMgQ3VzdG9taXplIHRoZSBoZWF0bWFwIGxheW91dAogICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgIGNvbHVtbl90aXRsZSA9ICJJbnRlcmVzdCIsCiAgICAgICAgcm93X3RpdGxlID0gIlRhcmdldCIsCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGF0ID0gYygwLCAxLCAyLCAzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMSIsICIyIiwgIjMiKSkpCgoKCmBgYAojIyMgREVHcyBmcm9tIFJOQS1zZXEKMi41a2IgZnJvbSBUU1MsIGF0IGxlYXN0IDEgYnAgb3ZlcmxhcAojIyMjIDJpCmBgYHtyfQpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSkgJT4lCiAgZHBseXI6OnNlbGVjdChWMSwgVFNTLCBWNikKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyIiwgIlRTUyIsICJlbnNlbWJsIikKCmRpZmYuUk5BIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5BNDg1LnNlbGVjdGVkMl9HMS4yaS5BNDg1X3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmRpZmYuUk5BIDwtIGRpZmYuUk5BICU+JSBkcGx5cjo6bGVmdF9qb2luKGdlbmUudGIsIGJ5ID0gYygiZW5zZW1ibF9nZW5lX2lkIiA9ICJlbnNlbWJsIikpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFRTUykpCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CgpkaWZmLlJOQSA8LSBkaWZmLlJOQSAlPiUgZHBseXI6Om11dGF0ZShkaWZmID0gY2FzZV93aGVuKHBhZGogPCBhbHBoYSAmIHNocmlua2VkX2xvZzJGQyA+IGZjQ3V0b2ZmIH4gIlVQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWRqIDwgYWxwaGEgJiBzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYgfiAiRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOTyIpKQoKCnRlbXAgPC0gZGlmZi5STkEgJT4lIGRwbHlyOjptdXRhdGUoc3RhcnQgPSBUU1MgLSAyNTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQgPSBUU1MgKyAyNTAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCwgZW5zZW1ibF9nZW5lX2lkLCBkaWZmKQoKCmRvd24uZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZGlmZiA9PSAiRE9XTiIpKQp1cC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJVUCIpKQpuby5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJOTyIpKQphbGwuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgpkYXRhIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCAiVFNTIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cC5nciwgbm8uZ3IsIGRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLmdyKQoKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQoKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3RpdGxlID0gIkludGVyZXN0IiwKICAgICAgICByb3dfdGl0bGUgPSAiVGFyZ2V0IiwKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoYXQgPSBjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxIiwgIjIiKSkpCgoKIyMgR08gVEVTVApkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuMmkuQTQ4NV92c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQpkaWZmLlJOQSA8LSBkaWZmLlJOQSAlPiUgZHBseXI6OmxlZnRfam9pbihnZW5lLnRiLCBieSA9IGMoImVuc2VtYmxfZ2VuZV9pZCIgPSAiZW5zZW1ibCIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShUU1MpKQphbHBoYSA8LSAwLjA1CmZjQ3V0b2ZmIDwtIDAuNQoKZGlmZi5STkEgPC0gZGlmZi5STkEgJT4lIGRwbHlyOjptdXRhdGUoZGlmZiA9IGNhc2Vfd2hlbihwYWRqIDwgYWxwaGEgJiBzaHJpbmtlZF9sb2cyRkMgPiBmY0N1dG9mZiB+ICJVUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkaiA8IGFscGhhICYgc2hyaW5rZWRfbG9nMkZDIDwgLWZjQ3V0b2ZmIH4gIkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTk8iKSkKZ2VuZUxpc3QgPC0gKGRpZmYuUk5BICU+JSBkcGx5cjo6ZmlsdGVyKGRpZmYgPT0gIkRPV04iKSkkZW5zZW1ibF9nZW5lX2lkCkdPIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCkdPLnJlYWRhYmxlIDwtIHNldFJlYWRhYmxlKEdPLCBPcmdEYiA9IG9yZy5NbS5lZy5kYikKCmRvd25TdGVtR2VuZSA8LSB1bmlxdWUodW5saXN0KChhcy5kYXRhLmZyYW1lKEdPKSAlPiUgZHBseXI6OnNsaWNlKGMoNCwgNSwgMTQsIDY2KSkgJT4lIGRwbHlyOjptdXRhdGUoZ2VuZUlEID0gc3Ryc3BsaXQoZ2VuZUlELCAiLyIpKSkkZ2VuZUlEKSkKZG93blN0ZW0uZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgZG93blN0ZW1HZW5lKSkKCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKZ2VuZUxpc3QgPC0gKGRpZmYuUk5BICU+JSBkcGx5cjo6ZmlsdGVyKGRpZmYgPT0gIlVQIikpJGVuc2VtYmxfZ2VuZV9pZApHTyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTy5yZWFkYWJsZSA8LSBzZXRSZWFkYWJsZShHTywgT3JnRGIgPSBvcmcuTW0uZWcuZGIpCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKCgpkb3duTk9OU3RlbS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIShlbnNlbWJsX2dlbmVfaWQgJWluJSBkb3duU3RlbUdlbmUpKSkKCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKZ2VuZUxpc3QgPC0gKGRpZmYuUk5BICU+JSBkcGx5cjo6ZmlsdGVyKGRpZmYgPT0gIlVQIikpJGVuc2VtYmxfZ2VuZV9pZApHTyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTy5yZWFkYWJsZSA8LSBzZXRSZWFkYWJsZShHTywgT3JnRGIgPSBvcmcuTW0uZWcuZGIpCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKCgoKIyMjIENoZWNraW5nIGJvb2ttYXJraW5nIG9ubHkgaW4gc3RlbSBnZW5lCgpkYXRhIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCAiVFNTIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb3duLmdyLCBkb3duTk9OU3RlbS5nciwgZG93blN0ZW0uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLmdyKQoKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQoKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3RpdGxlID0gIkludGVyZXN0IiwKICAgICAgICByb3dfdGl0bGUgPSAiVGFyZ2V0IiwKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoYXQgPSBjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxIiwgIjIiKSkpCmBgYAojIyMjIEVwaQpgYGB7cn0KZ2VuZS50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMykpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIFRTUywgVjYpCmNvbG5hbWVzKGdlbmUudGIpIDwtIGMoImNociIsICJUU1MiLCAiZW5zZW1ibCIpCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuRXBpLkE0ODVfdnNfRzEuRXBpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpCmRpZmYuUk5BIDwtIGRpZmYuUk5BICU+JSBkcGx5cjo6bGVmdF9qb2luKGdlbmUudGIsIGJ5ID0gYygiZW5zZW1ibF9nZW5lX2lkIiA9ICJlbnNlbWJsIikpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFRTUykpCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CgpkaWZmLlJOQSA8LSBkaWZmLlJOQSAlPiUgZHBseXI6Om11dGF0ZShkaWZmID0gY2FzZV93aGVuKHBhZGogPCBhbHBoYSAmIHNocmlua2VkX2xvZzJGQyA+IGZjQ3V0b2ZmIH4gIlVQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWRqIDwgYWxwaGEgJiBzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYgfiAiRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOTyIpKQoKCnRlbXAgPC0gZGlmZi5STkEgJT4lIGRwbHlyOjptdXRhdGUoc3RhcnQgPSBUU1MgLSAyNTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQgPSBUU1MgKyAyNTAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCwgZW5zZW1ibF9nZW5lX2lkLCBkaWZmKQoKCmRvd24uZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZGlmZiA9PSAiRE9XTiIpKQp1cC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJVUCIpKQpuby5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJOTyIpKQphbGwuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgpkYXRhIDwtIHJ1bkZpc2hlckV4YWN0Q29tYmluYXRpb25UYXJnZXQoIkgzSzI3YWNfZWZmaWUiLCAiVFNTIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cC5nciwgbm8uZ3IsIGRvd24uZ3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLmdyKQoKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQoKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBpbnRlcmVzdCwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGludGVyZXN0LCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGludGVyZXN0LCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbnRlcmVzdCwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3RpdGxlID0gIkludGVyZXN0IiwKICAgICAgICByb3dfdGl0bGUgPSAiVGFyZ2V0IiwKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoYXQgPSBjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxIiwgIjIiKSkpCgoKIyMgR08KZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLkVwaS5BNDg1X3ZzX0cxLkVwaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQpkaWZmLlJOQSA8LSBkaWZmLlJOQSAlPiUgZHBseXI6OmxlZnRfam9pbihnZW5lLnRiLCBieSA9IGMoImVuc2VtYmxfZ2VuZV9pZCIgPSAiZW5zZW1ibCIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShUU1MpKQphbHBoYSA8LSAwLjA1CmZjQ3V0b2ZmIDwtIDAuNQoKZGlmZi5STkEgPC0gZGlmZi5STkEgJT4lIGRwbHlyOjptdXRhdGUoZGlmZiA9IGNhc2Vfd2hlbihwYWRqIDwgYWxwaGEgJiBzaHJpbmtlZF9sb2cyRkMgPiBmY0N1dG9mZiB+ICJVUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkaiA8IGFscGhhICYgc2hyaW5rZWRfbG9nMkZDIDwgLWZjQ3V0b2ZmIH4gIkRPV04iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTk8iKSkKCmdlbmVMaXN0IDwtIChkaWZmLlJOQSAlPiUgZHBseXI6OmZpbHRlcihkaWZmID09ICJET1dOIikpJGVuc2VtYmxfZ2VuZV9pZApHTyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTy5yZWFkYWJsZSA8LSBzZXRSZWFkYWJsZShHTywgT3JnRGIgPSBvcmcuTW0uZWcuZGIpCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKZ2VuZUxpc3QgPC0gKGRpZmYuUk5BICU+JSBkcGx5cjo6ZmlsdGVyKGRpZmYgPT0gIlVQIikpJGVuc2VtYmxfZ2VuZV9pZApHTyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpHTy5yZWFkYWJsZSA8LSBzZXRSZWFkYWJsZShHTywgT3JnRGIgPSBvcmcuTW0uZWcuZGIpCnByaW50KGRvdHBsb3QoR08sIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICIiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjA1KSwgbG93ID0gInJlZCIsIGhpZ2ggPSAiYmxhY2siKSkKCmBgYAoKCiMjIFsyLjI1XSBDaGVja2luZyBnZW5lcyByZWxhdGVkIHRvIHJlZ3VsYXRvcnkgbG9vcHMKIyMjIGRUQUcsIENvbXBhcmluZyB0byBBc3luYwojIyMjIFAtUCwgUC1FCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3AtcGVfZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSAwLjIpCgppZC5HMVNwZWNpZmljUGVydCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfRzF2c0FzeW5jX0cxU3BlY2lmaWNQZXJ0LmJlZHBlIikpJFY3CmlkLkFzeW5jU3BlY2lmaWNQZXJ0IDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9HMXZzQXN5bmNfQXN5bmNTcGVjaWZpY1BlcnQuYmVkcGUiKSkkVjcKaWQuYm90aFBlcnQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0cxdnNBc3luY19ib3RoUGVydC5iZWRwZSIpKSRWNwppZC5ib3RoUmV0YWluZWQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0cxdnNBc3luY19ib3RoUmV0YWluZWQuYmVkcGUiKSkkVjcKCgpnZW5lTGlzdC5HMVNwZWNpZmljUGVydCA8LSAoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgaWQuRzFTcGVjaWZpY1BlcnQpICU+JSB1bm5lc3QoZ2VuZSkpJGdlbmUKZ2VuZUxpc3QuQXN5bmNTcGVjaWZpY1BlcnQgPC0gKGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGlkLkFzeW5jU3BlY2lmaWNQZXJ0KSAlPiUgdW5uZXN0KGdlbmUpKSRnZW5lCmdlbmVMaXN0LmJvdGhQZXJ0IDwtIChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBpZC5ib3RoUGVydCkgJT4lIHVubmVzdChnZW5lKSkkZ2VuZQpnZW5lTGlzdC5ib3RoUmV0YWluZWQgPC0gKGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGlkLmJvdGhSZXRhaW5lZCkgJT4lIHVubmVzdChnZW5lKSkkZ2VuZQoKR08uRzFTcGVjaWZpY1BlcnQuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QuRzFTcGVjaWZpY1BlcnQsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKSkKR08uQXN5bmNTcGVjaWZpY1Blci5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC5Bc3luY1NwZWNpZmljUGVydCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQpHTy5ib3RoUGVydC5kZiA8LSBhcy5kYXRhLmZyYW1lKGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC5ib3RoUGVydCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpKQpHTy5ib3RoUmV0YWluZWQuZGYgPC0gYXMuZGF0YS5mcmFtZShlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QuYm90aFJldGFpbmVkLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikpCgpzdWJzZXQuRzFTcGVjaWZpY1BlcnQgPC0gR08uRzFTcGVjaWZpY1BlcnQuZGYgJT4lIGRwbHlyOjpzZWxlY3QoSUQsIERlc2NyaXB0aW9uLCBHZW5lUmF0aW8sIHAuYWRqdXN0KSAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9ICJHMVNwZWNpZmljUGVydCIpICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBnciA9IHNhcHBseShHZW5lUmF0aW8sIGZ1bmN0aW9uKHgpIHsKICAgICAgIyBTcGxpdCB0aGUgc3RyaW5nIGJ5ICIvIgogICAgICBwYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi8iKSkKICAgICAgIyBDb252ZXJ0IHRvIG51bWVyaWMgYW5kIHBlcmZvcm0gdGhlIGRpdmlzaW9uCiAgICAgIGFzLm51bWVyaWMocGFydHNbMV0pIC8gYXMubnVtZXJpYyhwYXJ0c1syXSkKICAgIH0pCiAgKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhncikpCgpzdWJzZXQuQXN5bmNTcGVjaWZpY1BlcnQgPC0gR08uQXN5bmNTcGVjaWZpY1Blci5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gIkFzeW5jU3BlY2lmaWNQZXJ0IikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKCnN1YnNldC5ib3RoUGVydCA8LSBHTy5ib3RoUGVydC5kZiAlPiUgZHBseXI6OnNlbGVjdChJRCwgRGVzY3JpcHRpb24sIEdlbmVSYXRpbywgcC5hZGp1c3QpICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gImJvdGhQZXJ0IikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKCnN1YnNldC5ib3RoUmV0YWluZWQgPC0gR08uYm90aFJldGFpbmVkLmRmICU+JSBkcGx5cjo6c2VsZWN0KElELCBEZXNjcmlwdGlvbiwgR2VuZVJhdGlvLCBwLmFkanVzdCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSAiYm90aFJldGFpbmVkIikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGdyID0gc2FwcGx5KEdlbmVSYXRpbywgZnVuY3Rpb24oeCkgewogICAgICAjIFNwbGl0IHRoZSBzdHJpbmcgYnkgIi8iCiAgICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdCh4LCAiLyIpKQogICAgICAjIENvbnZlcnQgdG8gbnVtZXJpYyBhbmQgcGVyZm9ybSB0aGUgZGl2aXNpb24KICAgICAgYXMubnVtZXJpYyhwYXJ0c1sxXSkgLyBhcy5udW1lcmljKHBhcnRzWzJdKQogICAgfSkKICApICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGdyKSkKCmRhdGEgPC0gYmluZF9yb3dzKGJpbmRfcm93cyhzdWJzZXQuRzFTcGVjaWZpY1BlcnQsIHN1YnNldC5ib3RoUGVydCksIHN1YnNldC5ib3RoUmV0YWluZWQpCgpwIDwtIGdncGxvdChzdWJzZXQuRzFTcGVjaWZpY1BlcnQsIGFlcyh4ID0gZ3JvdXAsIHkgPSBEZXNjcmlwdGlvbiwgY29sb3IgPSBwLmFkanVzdCwgc2l6ZSA9IGdyKSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbGltaXRzID0gYygwLCAwLjA1KSkgKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgMykpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksICAjIFNldCBheGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLCAjIFNldCBheGlzIHRpdGxlIHNpemUgKGlmIG5vdCByZW1vdmVkKQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwgIyBTZXQgbGVnZW5kIHRleHQgc2l6ZQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIAoKYGBgCgojIyMgZFRBRwojIyMjIFAtUCwgUC1FCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3AtcGVfZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSAwLjIpCgpnZW5lTGlzdC51cExvb3AgPC0gdW5pcXVlKChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX2RUQUdfRE1TTyA9PSAiVVAiKSAlPiUgdW5uZXN0KGdlbmUpKSRnZW5lKQpnZW5lTGlzdC5ub0xvb3AgPC0gdW5pcXVlKChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX2RUQUdfRE1TTyA9PSAiTk8iKSAlPiUgdW5uZXN0KGdlbmUpKSRnZW5lKQpnZW5lTGlzdC5kb3duTG9vcCA8LSB1bmlxdWUoKGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fZFRBR19ETVNPID09ICJET1dOIikgJT4lIHVubmVzdChnZW5lKSkkZ2VuZSkKCgoKIyBDSEVDS0lORyBIT1cgTUFOWSBHRU5FUyBPVkVSTEFQIEFNT05HIFVQL05PL0RPV04Kc2V0c19saXN0IDwtIGxpc3QodXAgPSBnZW5lTGlzdC51cExvb3AsCiAgICAgICAgICAgICAgICAgIG5vID0gZ2VuZUxpc3Qubm9Mb29wLAogICAgICAgICAgICAgICAgICBkb3duID0gZ2VuZUxpc3QuZG93bkxvb3ApCgojIENyZWF0ZSB0aGUgRXVsZXIgcGxvdApldWxlcl9maXQgPC0gZXVsZXIoc2V0c19saXN0KQpwbG90KGV1bGVyX2ZpdCwKICAgICBsYWJlbHMgPSBUUlVFLCAgIyBEaXNwbGF5IHNldCBsYWJlbHMKICAgICBmaWxscyA9IFRSVUUsICAgIyBDb2xvciBmaWxsIHRoZSByZWdpb25zCiAgICAgcXVhbnRpdGllcyA9IFRSVUUpCgoKIyBHTwpHTy51cCA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QudXBMb29wLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy51cCkKR08ubm8gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0Lm5vTG9vcCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08ubm8pCkdPLmRvd24gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LmRvd25Mb29wLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5kb3duKQoKIyBHTyB0byBvbmx5IHNwZWNpZmljIHN1YnNldApnZW5lTGlzdC51cExvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC51cExvb3AsIHVuaW9uKGdlbmVMaXN0Lm5vTG9vcCwgZ2VuZUxpc3QuZG93bkxvb3ApKQpnZW5lTGlzdC5ub0xvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC5ub0xvb3AsIHVuaW9uKGdlbmVMaXN0LnVwTG9vcCwgZ2VuZUxpc3QuZG93bkxvb3ApKQpnZW5lTGlzdC5kb3duTG9vcC5zcGVjaWZpYyA8LSBzZXRkaWZmKGdlbmVMaXN0LmRvd25Mb29wLCB1bmlvbihnZW5lTGlzdC5ub0xvb3AsIGdlbmVMaXN0LnVwTG9vcCkpCkdPLnVwIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC51cExvb3Auc3BlY2lmaWMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLnVwKQpHTy5ubyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3Qubm9Mb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5ubykKR08uZG93biA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QuZG93bkxvb3Auc3BlY2lmaWMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLmRvd24pCgoKIyMgQ2hlY2tpbmcgcGVyY2VudGFnZSBvZiBib2JiaWUgZWFybHkgZ2VuZQoKIyMgSW1wb3J0aW5nIEJvYmJpZSBnZW5lIGNsYXNzaWZpY2F0aW9uCmdlbmVDbHVzdGVyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiYm9iYmllX2dlbmVfY2xhc3NpZmljYXRpb24uY3N2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZ2VuZSwgZW5zdCwgQ2x1c3RlcikKY29sbmFtZXMoZ2VuZUNsdXN0ZXIpIDwtIGMoImdlbmUiLCAiZW5zZW1ibF90cmFuc2NyaXB0X2lkIiwgImNsdXN0ZXIiKQoKCiMjIENvbnZlcnRpbmcgdHJhbnNjcmlwdCBJRCB0byBnZW5lIElECmlkUGFpcl90ZyA8LSBnZXRCTShhdHRyaWJ1dGVzID0gYygiZW5zZW1ibF90cmFuc2NyaXB0X2lkIiwgImVuc2VtYmxfZ2VuZV9pZCIpLAogICAgICAgICAgICAgICAgIGZpbHRlcnMgPSAiZW5zZW1ibF90cmFuc2NyaXB0X2lkIiwKICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBnZW5lQ2x1c3RlciRlbnNlbWJsX3RyYW5zY3JpcHQsCiAgICAgICAgICAgICAgICAgbWFydCA9IGVuc2VtYmwudjEwMikKZ2VuZUNsdXN0ZXIgPC0gZ2VuZUNsdXN0ZXIgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oaWRQYWlyX3RnLCBieSA9IGMoImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIpKQoKIyBNYWtpbmcgZGF0YSBmb3Igc3RhY2tlZCBiYXJwbG90CmNvdW50R2VuZSA8LSBmdW5jdGlvbihnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCBjbHVzdGVyTmFtZSl7CiAgbnVtIDwtIG5yb3coZ2VuZUNsdXN0ZXIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgZ3JvdXBOYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXIgJWluJSBjbHVzdGVyTmFtZSkpCiAgcmV0dXJuKG51bSkKfQpjb3VudEdlbmVMaXN0IDwtIGZ1bmN0aW9uKGdlbmVDbHVzdGVyLCBncm91cE5hbWUpewogIG4xIDwtIGNvdW50R2VuZShnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCAiRWFybHkiKQogIG4yIDwtIGNvdW50R2VuZShnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCAiTWlkZGxlIikKICBuMyA8LWNvdW50R2VuZShnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCAiTGF0ZSIpCiAgbjQgPC0gY291bnRHZW5lKGdlbmVDbHVzdGVyLCBncm91cE5hbWUsICJUcmFuc2llbnQiKQogIHJldHVybihjKG4xLCBuMiwgbjMsIG40KSkKfQoKZ3JvdXAgPC0gYyhyZXAoInVwIiwgNCksIHJlcCgibm8iLCA0KSwgcmVwKCJkb3duIiwgNCkpCmNsdXN0ZXIgPC0gcmVwKGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpLCAzKQpjbHVzdGVyIDwtIGZhY3RvcihjbHVzdGVyLCBsZXZlbHMgPSBjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSkKdmFsdWUgPC0gYyhjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBnZW5lTGlzdC51cExvb3ApLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdlbmVMaXN0Lm5vTG9vcCksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ2VuZUxpc3QuZG93bkxvb3ApKQoKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKZ2dwbG90KGRhdGEsIGFlcyhmaWxsPWNsdXN0ZXIsIHk9dmFsdWUsIHg9Z3JvdXApKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249InN0YWNrIiwgc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpCgp2YWx1ZSA8LSBjKGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdlbmVMaXN0LnVwTG9vcC5zcGVjaWZpYyksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ2VuZUxpc3Qubm9Mb29wLnNwZWNpZmljKSwKICAgICAgICAgICBjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBnZW5lTGlzdC5kb3duTG9vcC5zcGVjaWZpYykpCgpkYXRhIDwtIGRhdGEuZnJhbWUoZ3JvdXAsIGNsdXN0ZXIsIHZhbHVlKQojIFBsb3R0aW5nCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKYGBgCgoKIyMjIyBQLU4KYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yKQoKZ2VuZUxpc3QudXBMb29wIDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9kVEFHX0RNU08gPT0gIlVQIikgJT4lIHVubmVzdChnZW5lKSkkZ2VuZSkKZ2VuZUxpc3Qubm9Mb29wIDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9kVEFHX0RNU08gPT0gIk5PIikgJT4lIHVubmVzdChnZW5lKSkkZ2VuZSkKZ2VuZUxpc3QuZG93bkxvb3AgPC0gdW5pcXVlKChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX2RUQUdfRE1TTyA9PSAiRE9XTiIpICU+JSB1bm5lc3QoZ2VuZSkpJGdlbmUpCgoKCiMgQ0hFQ0tJTkcgSE9XIE1BTlkgR0VORVMgT1ZFUkxBUCBBTU9ORyBVUC9OTy9ET1dOCnNldHNfbGlzdCA8LSBsaXN0KHVwID0gZ2VuZUxpc3QudXBMb29wLAogICAgICAgICAgICAgICAgICBubyA9IGdlbmVMaXN0Lm5vTG9vcCwKICAgICAgICAgICAgICAgICAgZG93biA9IGdlbmVMaXN0LmRvd25Mb29wKQoKIyBDcmVhdGUgdGhlIEV1bGVyIHBsb3QKZXVsZXJfZml0IDwtIGV1bGVyKHNldHNfbGlzdCkKcGxvdChldWxlcl9maXQsCiAgICAgbGFiZWxzID0gVFJVRSwgICMgRGlzcGxheSBzZXQgbGFiZWxzCiAgICAgZmlsbHMgPSBUUlVFLCAgICMgQ29sb3IgZmlsbCB0aGUgcmVnaW9ucwogICAgIHF1YW50aXRpZXMgPSBUUlVFKQoKCiMgR08KR08udXAgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LnVwTG9vcCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08udXApCkdPLm5vIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC5ub0xvb3AsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLm5vKQpHTy5kb3duIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC5kb3duTG9vcCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08uZG93bikKCiMgR08gdG8gb25seSBzcGVjaWZpYyBzdWJzZXQKZ2VuZUxpc3QudXBMb29wLnNwZWNpZmljIDwtIHNldGRpZmYoZ2VuZUxpc3QudXBMb29wLCB1bmlvbihnZW5lTGlzdC5ub0xvb3AsIGdlbmVMaXN0LmRvd25Mb29wKSkKZ2VuZUxpc3Qubm9Mb29wLnNwZWNpZmljIDwtIHNldGRpZmYoZ2VuZUxpc3Qubm9Mb29wLCB1bmlvbihnZW5lTGlzdC51cExvb3AsIGdlbmVMaXN0LmRvd25Mb29wKSkKZ2VuZUxpc3QuZG93bkxvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC5kb3duTG9vcCwgdW5pb24oZ2VuZUxpc3Qubm9Mb29wLCBnZW5lTGlzdC51cExvb3ApKQpHTy51cCA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QudXBMb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy51cCkKR08ubm8gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0Lm5vTG9vcC5zcGVjaWZpYywgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08ubm8pCkdPLmRvd24gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LmRvd25Mb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5kb3duKQoKCiMjIENoZWNraW5nIHBlcmNlbnRhZ2Ugb2YgYm9iYmllIGVhcmx5IGdlbmUKCiMjIEltcG9ydGluZyBCb2JiaWUgZ2VuZSBjbGFzc2lmaWNhdGlvbgpnZW5lQ2x1c3RlciA8LSBmcmVhZChoZXJlKHJlZkRpciwgImJvYmJpZV9nZW5lX2NsYXNzaWZpY2F0aW9uLmNzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdlbmUsIGVuc3QsIENsdXN0ZXIpCmNvbG5hbWVzKGdlbmVDbHVzdGVyKSA8LSBjKCJnZW5lIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJjbHVzdGVyIikKCgojIyBDb252ZXJ0aW5nIHRyYW5zY3JpcHQgSUQgdG8gZ2VuZSBJRAppZFBhaXJfdGcgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJlbnNlbWJsX2dlbmVfaWQiKSwKICAgICAgICAgICAgICAgICBmaWx0ZXJzID0gImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsCiAgICAgICAgICAgICAgICAgdmFsdWVzID0gZ2VuZUNsdXN0ZXIkZW5zZW1ibF90cmFuc2NyaXB0LAogICAgICAgICAgICAgICAgIG1hcnQgPSBlbnNlbWJsLnYxMDIpCmdlbmVDbHVzdGVyIDwtIGdlbmVDbHVzdGVyICU+JSBkcGx5cjo6bGVmdF9qb2luKGlkUGFpcl90ZywgYnkgPSBjKCJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiKSkKCiMgTWFraW5nIGRhdGEgZm9yIHN0YWNrZWQgYmFycGxvdApjb3VudEdlbmUgPC0gZnVuY3Rpb24oZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgY2x1c3Rlck5hbWUpewogIG51bSA8LSBucm93KGdlbmVDbHVzdGVyICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGdyb3VwTmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyICVpbiUgY2x1c3Rlck5hbWUpKQogIHJldHVybihudW0pCn0KY291bnRHZW5lTGlzdCA8LSBmdW5jdGlvbihnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lKXsKICBuMSA8LSBjb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIkVhcmx5IikKICBuMiA8LSBjb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIk1pZGRsZSIpCiAgbjMgPC1jb3VudEdlbmUoZ2VuZUNsdXN0ZXIsIGdyb3VwTmFtZSwgIkxhdGUiKQogIG40IDwtIGNvdW50R2VuZShnZW5lQ2x1c3RlciwgZ3JvdXBOYW1lLCAiVHJhbnNpZW50IikKICByZXR1cm4oYyhuMSwgbjIsIG4zLCBuNCkpCn0KCmdyb3VwIDwtIGMocmVwKCJ1cCIsIDQpLCByZXAoIm5vIiwgNCksIHJlcCgiZG93biIsIDQpKQpjbHVzdGVyIDwtIHJlcChjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSwgMykKY2x1c3RlciA8LSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gYygiRWFybHkiLCAiTWlkZGxlIiwgIkxhdGUiLCAiVHJhbnNpZW50IikpCnZhbHVlIDwtIGMoY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ2VuZUxpc3QudXBMb29wKSwKICAgICAgICAgICBjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBnZW5lTGlzdC5ub0xvb3ApLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdlbmVMaXN0LmRvd25Mb29wKSkKCmRhdGEgPC0gZGF0YS5mcmFtZShncm91cCwgY2x1c3RlciwgdmFsdWUpCmdncGxvdChkYXRhLCBhZXMoZmlsbD1jbHVzdGVyLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKdmFsdWUgPC0gYyhjb3VudEdlbmVMaXN0KGdlbmVDbHVzdGVyLCBnZW5lTGlzdC51cExvb3Auc3BlY2lmaWMpLAogICAgICAgICAgIGNvdW50R2VuZUxpc3QoZ2VuZUNsdXN0ZXIsIGdlbmVMaXN0Lm5vTG9vcC5zcGVjaWZpYyksCiAgICAgICAgICAgY291bnRHZW5lTGlzdChnZW5lQ2x1c3RlciwgZ2VuZUxpc3QuZG93bkxvb3Auc3BlY2lmaWMpKQoKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKIyBQbG90dGluZwpnZ3Bsb3QoZGF0YSwgYWVzKGZpbGw9Y2x1c3RlciwgeT12YWx1ZSwgeD1ncm91cCkpICsgCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKZ2dwbG90KGRhdGEsIGFlcyhmaWxsPWNsdXN0ZXIsIHk9dmFsdWUsIHg9Z3JvdXApKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiLCBzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIENoZWNraW5nIGhvdyB0aG9zZSBnZW5lcyBiZWhhdmUgaW4gQTQ4NQpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuQTQ4NS5zZWxlY3RlZDJfRzEuMmkuQTQ4NV92c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQoKYWxwaGEgPC0gMC4wNQpmY0N1dG9mZiA8LSAwLjUKZGlmZi5STkEub3V0IDwtIGRpZmYuUk5BICU+JSBkcGx5cjo6bXV0YXRlKGRpZmYgPSBjYXNlX3doZW4ocGFkaiA8IGFscGhhICYgc2hyaW5rZWRfbG9nMkZDID4gZmNDdXRvZmYgfiAiVVAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZGogPCBhbHBoYSAmIHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZiB+ICJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5PIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVHcm91cCA9IGNhc2Vfd2hlbihlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lTGlzdC51cExvb3AgfiAiY29oZXNpbi11cExvb3AiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9nZW5lX2lkICVpbiUgZ2VuZUxpc3Qubm9Mb29wIH4gImNvaGVzaW4tbm9Mb29wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGdlbmVMaXN0LmRvd25Mb29wIH4gImNvaGVzaW4tZG93bkxvb3AiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOQSIpKQoKCmdncGxvdChkaWZmLlJOQS5vdXQsIGFlcyh4ID0gZ2VuZUdyb3VwLCBmaWxsID0gZGlmZikpICsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIpICsgdGhlbWVfYncoKQoKCnVwTG9vcC5kb3duUGVyYyA8LSBucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tdXBMb29wIiwgZGlmZiA9PSAiRE9XTiIpKS9ucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tdXBMb29wIikpCnVwTG9vcC51cFBlcmMgPC0gbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLXVwTG9vcCIsIGRpZmYgPT0gIlVQIikpL25yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi11cExvb3AiKSkKCm5vTG9vcC5kb3duUGVyYyA8LSBucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tbm9Mb29wIiwgZGlmZiA9PSAiRE9XTiIpKS9ucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tbm9Mb29wIikpCm5vTG9vcC51cFBlcmMgPC0gbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLW5vTG9vcCIsIGRpZmYgPT0gIlVQIikpL25yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi1ub0xvb3AiKSkKCmRvd25Mb29wLmRvd25QZXJjIDwtIG5yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi1kb3duTG9vcCIsIGRpZmYgPT0gIkRPV04iKSkvbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLWRvd25Mb29wIikpCmRvd25Mb29wLnVwUGVyYyA8LSBucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tZG93bkxvb3AiLCBkaWZmID09ICJVUCIpKS9ucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tZG93bkxvb3AiKSkKCgpkYXRhIDwtIHRpYmJsZShnZW5lR3JvdXAgPSBjKCJjb2hlc2luLXVwTG9vcCIsICJjb2hlc2luLXVwTG9vcCIsIAogICAgICAgICAgICAgICAgICAgICAiY29oZXNpbi1ub0xvb3AiLCAiY29oZXNpbi1ub0xvb3AiLCAKICAgICAgICAgICAgICAgICAgICAgImNvaGVzaW4tZG93bkxvb3AiLCAiY29oZXNpbi1kb3duTG9vcCIpLAogICAgICAgZGlmZiA9IHJlcChjKCJET1dOIiwgIlVQIiksIDMpLAogICAgICAgcGVyYyA9IGModXBMb29wLmRvd25QZXJjLCB1cExvb3AudXBQZXJjLCBub0xvb3AuZG93blBlcmMsIG5vTG9vcC51cFBlcmMsIGRvd25Mb29wLmRvd25QZXJjLCBkb3duTG9vcC51cFBlcmMpKjEwMCkKCmdncGxvdChkYXRhLCBhZXMoeCA9IGdlbmVHcm91cCwgeSA9IHBlcmMsIGZpbGwgPSBkaWZmICkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArIHRoZW1lX2J3KCkKCgoKCmdlbmVMaXN0Lm5vTG9vcFVuaXF1ZSA8LSBnZW5lTGlzdC5ub0xvb3BbIWdlbmVMaXN0Lm5vTG9vcCAlaW4lIHVuaXF1ZShjKGdlbmVMaXN0LmRvd25Mb29wLCBnZW5lTGlzdC51cExvb3ApKV0KZ2VuZUxpc3QuZG93bkxvb3BVbmlxdWUgPC0gZ2VuZUxpc3QuZG93bkxvb3BbIWdlbmVMaXN0LmRvd25Mb29wICVpbiUgdW5pcXVlKGMoZ2VuZUxpc3Qubm9Mb29wLCBnZW5lTGlzdC51cExvb3ApKV0KZ2VuZUxpc3QudXBMb29wVW5pcXVlIDwtIGdlbmVMaXN0LnVwTG9vcFshZ2VuZUxpc3QudXBMb29wICVpbiUgdW5pcXVlKGMoZ2VuZUxpc3Qubm9Mb29wLCBnZW5lTGlzdC5kb3duTG9vcCkpXQoKZGlmZi5STkEub3V0IDwtIGRpZmYuUk5BICU+JSBkcGx5cjo6bXV0YXRlKGRpZmYgPSBjYXNlX3doZW4ocGFkaiA8IGFscGhhICYgc2hyaW5rZWRfbG9nMkZDID4gZmNDdXRvZmYgfiAiVVAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZGogPCBhbHBoYSAmIHNocmlua2VkX2xvZzJGQyA8IC1mY0N1dG9mZiB+ICJET1dOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5PIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVHcm91cCA9IGNhc2Vfd2hlbihlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lTGlzdC51cExvb3BVbmlxdWUgIH4gImNvaGVzaW4tdXBMb29wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGdlbmVMaXN0Lm5vTG9vcFVuaXF1ZSB+ICJjb2hlc2luLW5vTG9vcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lTGlzdC5kb3duTG9vcFVuaXF1ZSB+ICJjb2hlc2luLWRvd25Mb29wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTkEiKSkKCgpnZ3Bsb3QoZGlmZi5STkEub3V0LCBhZXMoeCA9IGdlbmVHcm91cCwgZmlsbCA9IGRpZmYpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiKSArIHRoZW1lX2J3KCkKCgp1cExvb3AuZG93blBlcmMgPC0gbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLXVwTG9vcCIsIGRpZmYgPT0gIkRPV04iKSkvbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLXVwTG9vcCIpKQp1cExvb3AudXBQZXJjIDwtIG5yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi11cExvb3AiLCBkaWZmID09ICJVUCIpKS9ucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tdXBMb29wIikpCgpub0xvb3AuZG93blBlcmMgPC0gbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLW5vTG9vcCIsIGRpZmYgPT0gIkRPV04iKSkvbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLW5vTG9vcCIpKQpub0xvb3AudXBQZXJjIDwtIG5yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi1ub0xvb3AiLCBkaWZmID09ICJVUCIpKS9ucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tbm9Mb29wIikpCgpkb3duTG9vcC5kb3duUGVyYyA8LSBucm93KGRpZmYuUk5BLm91dCAlPiUgZHBseXI6OmZpbHRlcihnZW5lR3JvdXAgPT0gImNvaGVzaW4tZG93bkxvb3AiLCBkaWZmID09ICJET1dOIikpL25yb3coZGlmZi5STkEub3V0ICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmVHcm91cCA9PSAiY29oZXNpbi1kb3duTG9vcCIpKQpkb3duTG9vcC51cFBlcmMgPC0gbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLWRvd25Mb29wIiwgZGlmZiA9PSAiVVAiKSkvbnJvdyhkaWZmLlJOQS5vdXQgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZUdyb3VwID09ICJjb2hlc2luLWRvd25Mb29wIikpCgoKZGF0YSA8LSB0aWJibGUoZ2VuZUdyb3VwID0gYygiY29oZXNpbi11cExvb3AiLCAiY29oZXNpbi11cExvb3AiLCAKICAgICAgICAgICAgICAgICAgICAgImNvaGVzaW4tbm9Mb29wIiwgImNvaGVzaW4tbm9Mb29wIiwgCiAgICAgICAgICAgICAgICAgICAgICJjb2hlc2luLWRvd25Mb29wIiwgImNvaGVzaW4tZG93bkxvb3AiKSwKICAgICAgIGRpZmYgPSByZXAoYygiRE9XTiIsICJVUCIpLCAzKSwKICAgICAgIHBlcmMgPSBjKHVwTG9vcC5kb3duUGVyYywgdXBMb29wLnVwUGVyYywgbm9Mb29wLmRvd25QZXJjLCBub0xvb3AudXBQZXJjLCBkb3duTG9vcC5kb3duUGVyYywgZG93bkxvb3AudXBQZXJjKSoxMDApCgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBnZW5lR3JvdXAsIHkgPSBwZXJjLCBmaWxsID0gZGlmZiApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKyB0aGVtZV9idygpCgpgYGAKIyMjIEE0ODUKIyMjIyBQLVAsIFAtRQpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLXBlX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yKQoKZ2VuZUxpc3QudXBMb29wIDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9BNDg1X0RNU08gPT0gIlVQIikgJT4lIHVubmVzdChnZW5lKSkkZ2VuZSkKZ2VuZUxpc3Qubm9Mb29wIDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9BNDg1X0RNU08gPT0gIk5PIikgJT4lIHVubmVzdChnZW5lKSkkZ2VuZSkKZ2VuZUxpc3QuZG93bkxvb3AgPC0gdW5pcXVlKChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX0E0ODVfRE1TTyA9PSAiRE9XTiIpICU+JSB1bm5lc3QoZ2VuZSkpJGdlbmUpCgoKCiMgQ0hFQ0tJTkcgSE9XIE1BTlkgR0VORVMgT1ZFUkxBUCBBTU9ORyBVUC9OTy9ET1dOCnNldHNfbGlzdCA8LSBsaXN0KHVwID0gZ2VuZUxpc3QudXBMb29wLAogICAgICAgICAgICAgICAgICBubyA9IGdlbmVMaXN0Lm5vTG9vcCwKICAgICAgICAgICAgICAgICAgZG93biA9IGdlbmVMaXN0LmRvd25Mb29wKQoKIyBDcmVhdGUgdGhlIEV1bGVyIHBsb3QKZXVsZXJfZml0IDwtIGV1bGVyKHNldHNfbGlzdCkKcGxvdChldWxlcl9maXQsCiAgICAgbGFiZWxzID0gVFJVRSwgICMgRGlzcGxheSBzZXQgbGFiZWxzCiAgICAgZmlsbHMgPSBUUlVFLCAgICMgQ29sb3IgZmlsbCB0aGUgcmVnaW9ucwogICAgIHF1YW50aXRpZXMgPSBUUlVFKQoKCiMgR08KR08udXAgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LnVwTG9vcCwgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08udXAsIHNob3dDYXRlZ29yeSA9IDE1KQpHTy5ubyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3Qubm9Mb29wLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5ubywgc2hvd0NhdGVnb3J5ID0gMTUpCkdPLmRvd24gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LmRvd25Mb29wLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5kb3duLCBzaG93Q2F0ZWdvcnkgPSAyMCkKCiMgR08gdG8gb25seSBzcGVjaWZpYyBzdWJzZXQKZ2VuZUxpc3QudXBMb29wLnNwZWNpZmljIDwtIHNldGRpZmYoZ2VuZUxpc3QudXBMb29wLCB1bmlvbihnZW5lTGlzdC5ub0xvb3AsIGdlbmVMaXN0LmRvd25Mb29wKSkKZ2VuZUxpc3Qubm9Mb29wLnNwZWNpZmljIDwtIHNldGRpZmYoZ2VuZUxpc3Qubm9Mb29wLCB1bmlvbihnZW5lTGlzdC51cExvb3AsIGdlbmVMaXN0LmRvd25Mb29wKSkKZ2VuZUxpc3QuZG93bkxvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC5kb3duTG9vcCwgdW5pb24oZ2VuZUxpc3Qubm9Mb29wLCBnZW5lTGlzdC51cExvb3ApKQpHTy51cCA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QudXBMb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy51cCkKR08ubm8gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0Lm5vTG9vcC5zcGVjaWZpYywgT3JnRGIgPSBvcmcuTW0uZWcuZGIsIGtleVR5cGUgPSAiRU5TRU1CTCIsIG9udCA9ICJCUCIpCmRvdHBsb3QoR08ubm8pCkdPLmRvd24gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVMaXN0LmRvd25Mb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5kb3duLCBzaG93Q2F0ZWdvcnkgPSAyMCkKCgpgYGAKCiMjIyMgUC1OCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMikKCmdlbmVMaXN0LnVwTG9vcCA8LSB1bmlxdWUoKGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fQTQ4NV9ETVNPID09ICJVUCIpICU+JSB1bm5lc3QoZ2VuZSkpJGdlbmUpCmdlbmVMaXN0Lm5vTG9vcCA8LSB1bmlxdWUoKGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fQTQ4NV9ETVNPID09ICJOTyIpICU+JSB1bm5lc3QoZ2VuZSkpJGdlbmUpCmdlbmVMaXN0LmRvd25Mb29wIDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9BNDg1X0RNU08gPT0gIkRPV04iKSAlPiUgdW5uZXN0KGdlbmUpKSRnZW5lKQoKCgojIENIRUNLSU5HIEhPVyBNQU5ZIEdFTkVTIE9WRVJMQVAgQU1PTkcgVVAvTk8vRE9XTgpzZXRzX2xpc3QgPC0gbGlzdCh1cCA9IGdlbmVMaXN0LnVwTG9vcCwKICAgICAgICAgICAgICAgICAgbm8gPSBnZW5lTGlzdC5ub0xvb3AsCiAgICAgICAgICAgICAgICAgIGRvd24gPSBnZW5lTGlzdC5kb3duTG9vcCkKCiMgQ3JlYXRlIHRoZSBFdWxlciBwbG90CmV1bGVyX2ZpdCA8LSBldWxlcihzZXRzX2xpc3QpCnBsb3QoZXVsZXJfZml0LAogICAgIGxhYmVscyA9IFRSVUUsICAjIERpc3BsYXkgc2V0IGxhYmVscwogICAgIGZpbGxzID0gVFJVRSwgICAjIENvbG9yIGZpbGwgdGhlIHJlZ2lvbnMKICAgICBxdWFudGl0aWVzID0gVFJVRSkKCgojIEdPCkdPLnVwIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC51cExvb3AsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLnVwKQpHTy5ubyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3Qubm9Mb29wLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5ubykKR08uZG93biA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QuZG93bkxvb3AsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLmRvd24sIHNob3dDYXRlZ29yeSA9IDIwKQoKIyBHTyB0byBvbmx5IHNwZWNpZmljIHN1YnNldApnZW5lTGlzdC51cExvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC51cExvb3AsIHVuaW9uKGdlbmVMaXN0Lm5vTG9vcCwgZ2VuZUxpc3QuZG93bkxvb3ApKQpnZW5lTGlzdC5ub0xvb3Auc3BlY2lmaWMgPC0gc2V0ZGlmZihnZW5lTGlzdC5ub0xvb3AsIHVuaW9uKGdlbmVMaXN0LnVwTG9vcCwgZ2VuZUxpc3QuZG93bkxvb3ApKQpnZW5lTGlzdC5kb3duTG9vcC5zcGVjaWZpYyA8LSBzZXRkaWZmKGdlbmVMaXN0LmRvd25Mb29wLCB1bmlvbihnZW5lTGlzdC5ub0xvb3AsIGdlbmVMaXN0LnVwTG9vcCkpCkdPLnVwIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lTGlzdC51cExvb3Auc3BlY2lmaWMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLnVwKQpHTy5ubyA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3Qubm9Mb29wLnNwZWNpZmljLCBPcmdEYiA9IG9yZy5NbS5lZy5kYiwga2V5VHlwZSA9ICJFTlNFTUJMIiwgb250ID0gIkJQIikKZG90cGxvdChHTy5ubykKR08uZG93biA8LSBlbnJpY2hHTyhnZW5lID0gZ2VuZUxpc3QuZG93bkxvb3Auc3BlY2lmaWMsIE9yZ0RiID0gb3JnLk1tLmVnLmRiLCBrZXlUeXBlID0gIkVOU0VNQkwiLCBvbnQgPSAiQlAiKQpkb3RwbG90KEdPLmRvd24pCgoKYGBgCiMjIFsyLjI2XSBDaGVja2luZyB0aGUgQ2hJUCBpbnRlbnNpdHkgYXQgYW5jaG9ycwpUaGlzIGRvZXNuJ3QgaGF2ZSB0byBiZSByZXN0cmljdGVkIHRvIFAtTiBsb29wcy4gTGV0J3MgY2hlY2sgYWxsIGxvb3BzIGZpcnN0LgpBbHNvIGluc3RlYWQgb2YgZGVuc2l0eSAobWVhbiksIG1lZGlhbiBjb3VsZCBiZSBiZXR0ZXIgY2hvaWNlLiBTdW0gaXMgbm90IGFwcHJvcHJpYXRlIGhlcmUgc2luY2UKdGhlIHNpemUgb2YgYW5jaG9ycyBhcmUgbm90IHNhbWUuCiMjIyMgTGltaXRlZCB0byBwZWFrcyB0byByZWR1Y2Ugbm9pc2UKIyMjIyMgZFRBRwpgYGB7cn0KZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGxvb3AgPT1ncm91cDEpICkkc3VtU2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIobG9vcCA9PWdyb3VwMikgKSRzdW1TY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgojIFVQIGxvb3AKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci51cCA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwKSkKIyBOTyBsb29wCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQphbmNob3Iubm8gPC0gKGV4dHJhY3RBbmNob3IobG9vcC5ubykpCiMgVVAgTk8KbG9vcC51cG5vIDwtIGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKQphbmNob3IudXBubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLnVwbm8pKQojIERPV04gbG9vcApsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5kb3duIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuZG93bikpCgpnZXRTdW1TY29yZXMgPC0gZnVuY3Rpb24odHJhY2ssIGFuY2hvcikgewogICMgRmluZCBvdmVybGFwcyBiZXR3ZWVuIGFsbCBhbmNob3JzIGFuZCB0cmFjayByZWdpb25zIGF0IG9uY2UKICBvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLCB0cmFjaykKICAKICAjIEV4dHJhY3QgdGhlIHNjb3JlcyBhbmQgY29ycmVzcG9uZGluZyBhbmNob3IgaW5kaWNlcwogIGFuY2hvcl9pbmRpY2VzIDwtIHF1ZXJ5SGl0cyhvdmVybGFwcykKICB0cmFja19zY29yZXMgPC0gc2NvcmUodHJhY2spW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0KICAKICAjIFVzZSB0YXBwbHkgdG8gY2FsY3VsYXRlIHRoZSBtZWRpYW4gc2NvcmVzIGZvciBlYWNoIGFuY2hvcgogIG1lZGlhbl9zY29yZXMgPC0gdGFwcGx5KHRyYWNrX3Njb3JlcywgYW5jaG9yX2luZGljZXMsIG1lYW4sIG5hLnJtID0gVFJVRSkKICAKICAjIEluaXRpYWxpemUgYSBudW1lcmljIHZlY3RvciB0byBzdG9yZSB0aGUgbWVkaWFuIHNjb3JlcyBmb3IgZWFjaCBhbmNob3IKICBhbGxfbWVkaWFuX3Njb3JlcyA8LSByZXAoTkEsIGxlbmd0aChhbmNob3IpKQogIAogICMgUG9wdWxhdGUgdGhlIG1lZGlhbiBzY29yZXMgZm9yIHRoZSBhbmNob3JzIHRoYXQgaGF2ZSBvdmVybGFwcwogIGFsbF9tZWRpYW5fc2NvcmVzW2FzLm51bWVyaWMobmFtZXMobWVkaWFuX3Njb3JlcykpXSA8LSBtZWRpYW5fc2NvcmVzCiAgCiAgcmV0dXJuKGFsbF9tZWRpYW5fc2NvcmVzKQp9CgpwbG90U3VtU2NvcmVzIDwtIGZ1bmN0aW9uKHRyYWNrLCBwZWFrLCBuYW1lKXsKICBwZWFrVHJhY2sgPC0gdHJhY2tbdW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHModHJhY2ssIHBlYWspKSldCiAgYSA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IudXApCiAgYiA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3Iubm8pCiAgYyA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IuZG93bikKICBhLnRiIDwtIHRpYmJsZShsb29wID0gIlVQIiwKICAgICAgICAgICAgICAgICBzdW1TY29yZSA9IGEpCiAgYi50YiA8LSB0aWJibGUobG9vcCA9ICJOTyIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBiKQogIGMudGIgPC0gdGliYmxlKGxvb3AgPSAiRE9XTiIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBjKQogIGRhdGEgPC0gYmluZF9yb3dzKGEudGIsIGIudGIsIGMudGIpICU+JSBkcm9wX25hKCkKICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBsb29wLCB5ID0gc3VtU2NvcmUpKSArIAogICAgbGFicyh4ID0gTlVMTCwgeSA9IHBhc3RlMChuYW1lLCAiIGF2ZXJhZ2UgcGVhayBzY29yZSBwZXIgYW5jaG9yIikpICsKICAgIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDEsIG91dGxpZXIuc3Ryb2tlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsKICAgIHN0YXRfc3VtbWFyeSgKICAgICAgYWVzKGdyb3VwID0gbG9vcCksIGZ1biA9IG1lYW4sCiAgICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIHF1YW50aWxlKGRhdGEkc3VtU2NvcmUsIDAuOTUpKSkgKyB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkKfQoKcGxvdFN1bVNjb3Jlc0JpbmFyeSA8LSBmdW5jdGlvbih0cmFjaywgcGVhaywgbmFtZSwgYW5jaG9yLnVwbm8sIGFuY2hvci5kb3duKXsKICBwZWFrVHJhY2sgPC0gdHJhY2tbdW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHModHJhY2ssIHBlYWspKSldCiAgYiA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IudXBubykKICBjIDwtIGdldFN1bVNjb3JlcyhwZWFrVHJhY2ssIGFuY2hvci5kb3duKQogIGIudGIgPC0gdGliYmxlKGxvb3AgPSAiVVAvTk8iLAogICAgICAgICAgICAgICAgIHN1bVNjb3JlID0gYikKICBjLnRiIDwtIHRpYmJsZShsb29wID0gIkRPV04iLAogICAgICAgICAgICAgICAgIHN1bVNjb3JlID0gYykKICBkYXRhIDwtIGJpbmRfcm93cyhiLnRiLCBjLnRiKSAlPiUgZHJvcF9uYSgpCiAgZGF0YSRsb29wIDwtIGZhY3RvcihkYXRhJGxvb3AsIGxldmVscyA9IGMoIlVQL05PIiwgIkRPV04iKSkKICAKICBwMTIgPC0gZ2V0UHZhbFdpbGNveChkYXRhLCAiVVAvTk8iLCAiRE9XTiIpCiAgcCA8LSAgZ2dwbG90KGRhdGEsIGFlcyh4ID0gbmFtZSwgZmlsbCA9IGxvb3AsIHkgPSBzdW1TY29yZSkpICsgCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gcGFzdGUwKCJBdmVyYWdlIENoSVAgcGVhayBzY29yZSBhdCBhbmNob3IpIikpICsKICAgIGludHJvZGF0YXZpejo6Z2VvbV9zcGxpdF92aW9saW4obGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjQpICsKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgICBzdGF0X3N1bW1hcnkoCiAgICAgIGFlcyhncm91cCA9IGxvb3ApLCBmdW4gPSBtZWFuLAogICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICAgICkgKyB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZU0sIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgICApLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgICksCiAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICAgICksCiAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgICApLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgICApICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMocXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC4wKSwgcXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC45KSkpICsgCiAgICBhbm5vdGF0ZSgKICAgICAidGV4dCIsIHggPSAxLCB5ID0gcXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC41KSwKICAgICBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMikpLAogICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMwogICApICsgICBndWlkZXMoCiAgICBmaWxsID0gZ3VpZGVfbGVnZW5kKAogICAgICAgIGtleXdpZHRoID0gMC4yLCAgIyBBZGp1c3QgdGhlIHdpZHRoIG9mIHRoZSBsZWdlbmQga2V5cwogICAgICAgIGtleWhlaWdodCA9IDAuMiAgIyBBZGp1c3QgdGhlIGhlaWdodCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICkKICApCiAgCiAgIGZpbGVOYW1lIDwtIHBhc3RlMCgiQ2hJUF9wZWFrX2F2Z1BlYWtTY29yZV8iLCBuYW1lKQogIHdpZHRoIDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCiAgaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCiMgU3VtIHBlYWsgc2NvcmUKIyMjIwp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTVfSDNLNG1lM18wNC03NDVfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCiNwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiSDNLNG1lMyIpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJIM0s0bWUzIiwgYW5jaG9yLnVwbm8sIGFuY2hvci5kb3duKQoKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLmJ3IiksIGZvcm1hdCA9ICJCaWdXaWciKQpwZWFrIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJHU00yNDM4NDc2X0VDLURHLTM0NTgtSDNLMjdBQ19BU1lOXzEubmFycm93UGVhay5iZWQiKSkKI3Bsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJIM0syN2FjIikKcGxvdFN1bVNjb3Jlc0JpbmFyeSh0cmFjaywgcGVhaywgIkgzSzI3YWMiLCBhbmNob3IudXBubywgYW5jaG9yLmRvd24pCgp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICJHU00yNjgzNDQwX0oxX0gzSzE0YWNfbW0xMExpZnRlZC5ibGFjay5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjY4MzQ0MF9KMV9IM0sxNGFjX21tMTBMaWZ0ZWQuYmVkIikpCiNwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiSDNLMTRhYyIpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJIM0sxNGFjIiwgYW5jaG9yLnVwbm8sIGFuY2hvci5kb3duKQoKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF90cmltX3EyMF9kZWR1cF9ibGFja19kZXB0aE5vcm0uYnciKSwgZm9ybWF0ID0gIkJpZ1dpZyIpCnBlYWsgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjQ4X0NUQ0ZfMDctNzI5X0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQojcGxvdFN1bVNjb3Jlcyh0cmFjaywgcGVhaywgIkNUQ0YiKQpwbG90U3VtU2NvcmVzQmluYXJ5KHRyYWNrLCBwZWFrLCAiQ1RDRiIsIGFuY2hvci51cG5vLCBhbmNob3IuZG93bikKCnRyYWNrIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfdHJpbV9xMjBfZGVkdXBfYmxhY2tfZGVwdGhOb3JtLmJ3IiksIGZvcm1hdCA9ICJCaWdXaWciKQpwZWFrIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICIzMzI1MF9SQUQyMV9hYjk5Ml9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay5iZWQiKSkKI3Bsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJSQUQyMSIpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJSQUQyMSIsIGFuY2hvci51cG5vLCBhbmNob3IuZG93bikKCgpgYGAKIyMjIyMgQTQ4NQpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCiMgVVAgbG9vcApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQojIE5PIGxvb3AKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5ubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLm5vKSkKIyBET1dOIGxvb3AKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmRvd24pKQoKZ2V0U3VtU2NvcmVzIDwtIGZ1bmN0aW9uKHRyYWNrLCBhbmNob3IpIHsKICAjIEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBhbGwgYW5jaG9ycyBhbmQgdHJhY2sgcmVnaW9ucyBhdCBvbmNlCiAgb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvciwgdHJhY2spCiAgCiAgIyBFeHRyYWN0IHRoZSBzY29yZXMgYW5kIGNvcnJlc3BvbmRpbmcgYW5jaG9yIGluZGljZXMKICBhbmNob3JfaW5kaWNlcyA8LSBxdWVyeUhpdHMob3ZlcmxhcHMpCiAgdHJhY2tfc2NvcmVzIDwtIHNjb3JlKHRyYWNrKVtzdWJqZWN0SGl0cyhvdmVybGFwcyldCiAgCiAgIyBVc2UgdGFwcGx5IHRvIGNhbGN1bGF0ZSB0aGUgbWVkaWFuIHNjb3JlcyBmb3IgZWFjaCBhbmNob3IKICBtZWRpYW5fc2NvcmVzIDwtIHRhcHBseSh0cmFja19zY29yZXMsIGFuY2hvcl9pbmRpY2VzLCBzdW0sIG5hLnJtID0gVFJVRSkKICAKICAjIEluaXRpYWxpemUgYSBudW1lcmljIHZlY3RvciB0byBzdG9yZSB0aGUgbWVkaWFuIHNjb3JlcyBmb3IgZWFjaCBhbmNob3IKICBhbGxfbWVkaWFuX3Njb3JlcyA8LSByZXAoTkEsIGxlbmd0aChhbmNob3IpKQogIAogICMgUG9wdWxhdGUgdGhlIG1lZGlhbiBzY29yZXMgZm9yIHRoZSBhbmNob3JzIHRoYXQgaGF2ZSBvdmVybGFwcwogIGFsbF9tZWRpYW5fc2NvcmVzW2FzLm51bWVyaWMobmFtZXMobWVkaWFuX3Njb3JlcykpXSA8LSBtZWRpYW5fc2NvcmVzCiAgCiAgcmV0dXJuKGFsbF9tZWRpYW5fc2NvcmVzKQp9CgpwbG90U3VtU2NvcmVzIDwtIGZ1bmN0aW9uKHRyYWNrLCBwZWFrLCBuYW1lKXsKICBwZWFrVHJhY2sgPC0gdHJhY2tbdW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHModHJhY2ssIHBlYWspKSldCiAgYSA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IudXApCiAgYiA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3Iubm8pCiAgYyA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IuZG93bikKICBhLnRiIDwtIHRpYmJsZShsb29wID0gIlVQIiwKICAgICAgICAgICAgICAgICBzdW1TY29yZSA9IGEpCiAgYi50YiA8LSB0aWJibGUobG9vcCA9ICJOTyIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBiKQogIGMudGIgPC0gdGliYmxlKGxvb3AgPSAiRE9XTiIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBjKQogIGRhdGEgPC0gYmluZF9yb3dzKGEudGIsIGIudGIsIGMudGIpICU+JSBkcm9wX25hKCkKICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBsb29wLCB5ID0gc3VtU2NvcmUpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAobmFtZSwgIiBzdW0gcGVhayIpKSArCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgcXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC45KSkpCn0KCiMgU3VtIHBlYWsgc2NvcmUKIyMjIwp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTVfSDNLNG1lM18wNC03NDVfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJIM0s0bWUzIikKCnRyYWNrIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIkdTTTI0Mzg0NzZfRUMtREctMzQ1OC1IM0syN0FDX0FTWU5fMS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCnBsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJIM0syN2FjIikKCnRyYWNrIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIkdTTTI2ODM0NDBfSjFfSDNLMTRhY19tbTEwTGlmdGVkLmJsYWNrLmJ3IiksIGZvcm1hdCA9ICJCaWdXaWciKQpwZWFrIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJHU00yNjgzNDQwX0oxX0gzSzE0YWNfbW0xMExpZnRlZC5iZWQiKSkKcGxvdFN1bVNjb3Jlcyh0cmFjaywgcGVhaywgIkgzSzE0YWMiKQoKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF90cmltX3EyMF9kZWR1cF9ibGFja19kZXB0aE5vcm0uYnciKSwgZm9ybWF0ID0gIkJpZ1dpZyIpCnBlYWsgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjQ4X0NUQ0ZfMDctNzI5X0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQpwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiQ1RDRiIpCgp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI1MF9SQUQyMV9hYjk5Ml9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhay50ZW1wIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiMzMyNTBfUkFEMjFfYWI5OTJfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVjIgPSBWMiAtIDEwMDAsCiAgICAgICAgICAgICAgICBWMyA9IFYzICsgMTAwMCkKY29sbmFtZXMocGVhay50ZW1wKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKcGVhayA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocGVhay50ZW1wKQpwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiWVkxIikKCgojIyMgRm9yIHRob3NlIHdpdGggb25seSBzdW1taXQKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiR1NNNTU3MTg5NV9FU0NfWVkxXzEuYnciKSwgZm9ybWF0ID0gIkJpZ1dpZyIpCnBlYWsgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIkdTTTU1NzE4OTVfRVNDX1lZMV9zdW1taXQuYmVkIikpCnBsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJSQUQyMSIpCgojIyMgRk9SIFRIT1NFIFdJVEhPVVQgUEVBS1MKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiR1NNMjA4MjcwOF9FU0MuSDNLMjdtZTMuMV9tbTEwTGlmdGVkLmJsYWNrLmJ3IiksIGZvcm1hdCA9ICJCaWdXaWciKQphIDwtIGdldFN1bVNjb3Jlcyh0cmFjaywgYW5jaG9yLnVwKQpiIDwtIGdldFN1bVNjb3Jlcyh0cmFjaywgYW5jaG9yLm5vKQpjIDwtIGdldFN1bVNjb3Jlcyh0cmFjaywgYW5jaG9yLmRvd24pCmEudGIgPC0gdGliYmxlKGxvb3AgPSAiVVAiLAogICAgICAgICAgICAgICBzdW1TY29yZSA9IGEpCmIudGIgPC0gdGliYmxlKGxvb3AgPSAiTk8iLAogICAgICAgICAgICAgICBzdW1TY29yZSA9IGIpCmMudGIgPC0gdGliYmxlKGxvb3AgPSAiRE9XTiIsCiAgICAgICAgICAgICAgIHN1bVNjb3JlID0gYykKZGF0YSA8LSBiaW5kX3Jvd3MoYS50YiwgYi50YiwgYy50YikgJT4lIGRyb3BfbmEoKQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBsb29wLCB5ID0gc3VtU2NvcmUpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAoIkgzSzI3bWUzIHN1bSBubyBwZWFrIikpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgcXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC45KSkpCmBgYAojIyMjIFBlYWsgZGVuc2l0eSBpbnN0ZWFkIG9mIGludGVuc2l0eQpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCiMgVVAgbG9vcApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQojIE5PIGxvb3AKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5ubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLm5vKSkKIyBET1dOIGxvb3AKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmRvd24pKQoKCnBlYWsuSDNLNG1lMyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTVfSDNLNG1lM18wNC03NDVfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBlYWsuSDNLMjdhYyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCnBlYWsuQ1RDRiA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBlYWsudGVtcCA8LSBmcmVhZChoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFYyID0gVjIgLSAxMDAwLAogICAgICAgICAgICAgICAgVjMgPSBWMyArIDEwMDApCmNvbG5hbWVzKHBlYWsudGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCnBlYWsuUkFEMjEgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHBlYWsudGVtcCkKCgpjYWxjdWxhdGVQZWFrRGVuc2l0eSA8LSBmdW5jdGlvbihwZWFrLCBub3RlKXsKICAKICBvdmVybGFwX2NvdW50cyA8LSBjb3VudE92ZXJsYXBzKGFuY2hvci51cCwgcGVhaykKICBhbmNob3Jfd2lkdGhzIDwtICh3aWR0aChhbmNob3IudXApLTEpLzEwMDAKICBkZW5zaXR5IDwtIG92ZXJsYXBfY291bnRzIC8gYW5jaG9yX3dpZHRocwogIGRhdGExIDwtIHRpYmJsZSh0eXBlID0gIlVQIiwKICAgICAgICAgICAgICAgICAgZGVuc2l0eVBlcktiID0gZGVuc2l0eSkKICAKICBvdmVybGFwX2NvdW50cyA8LSBjb3VudE92ZXJsYXBzKGFuY2hvci5ubywgcGVhaykKICBhbmNob3Jfd2lkdGhzIDwtICh3aWR0aChhbmNob3Iubm8pLTEpLzEwMDAKICBkZW5zaXR5IDwtIG92ZXJsYXBfY291bnRzIC8gYW5jaG9yX3dpZHRocwogIG1jb2xzKGFuY2hvci5ubykkZGVuc2l0eSA8LSBkZW5zaXR5CiAgZGF0YTIgPC0gdGliYmxlKHR5cGUgPSAiTk8iLAogICAgICAgICAgICAgICAgICBkZW5zaXR5UGVyS2IgPSBkZW5zaXR5KQogIAogIG92ZXJsYXBfY291bnRzIDwtIGNvdW50T3ZlcmxhcHMoYW5jaG9yLmRvd24sIHBlYWspCiAgYW5jaG9yX3dpZHRocyA8LSAod2lkdGgoYW5jaG9yLmRvd24pLTEpLzEwMDAKICBkZW5zaXR5IDwtIG92ZXJsYXBfY291bnRzIC8gYW5jaG9yX3dpZHRocwogIG1jb2xzKGFuY2hvci5kb3duKSRkZW5zaXR5IDwtIGRlbnNpdHkKICBkYXRhMyA8LSB0aWJibGUodHlwZSA9ICJET1dOIiwKICAgICAgICAgICAgICAgICAgZGVuc2l0eVBlcktiID0gZGVuc2l0eSkKICAKICBkYXRhIDwtIGJpbmRfcm93cyhkYXRhMSwgZGF0YTIsIGRhdGEzKQogIAogIGdncGxvdChkYXRhLCBhZXMoeCA9IHR5cGUsIHkgPSBkZW5zaXR5UGVyS2IpKSAgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjEgKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKG5vdGUpICsKICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCBxdWFudGlsZShkYXRhJHN1bVNjb3JlLCAwLjkpKSkKfQoKY2FsY3VsYXRlUGVha0RlbnNpdHkocGVhay5IM0s0bWUzLCAiSDNLNG1lMyIpCmNhbGN1bGF0ZVBlYWtEZW5zaXR5KHBlYWsuSDNLMjdhYywgIkgzSzI3YWMiKQpjYWxjdWxhdGVQZWFrRGVuc2l0eShwZWFrLkNUQ0YsICJDVENGIikKY2FsY3VsYXRlUGVha0RlbnNpdHkocGVhay5SQUQyMSwgIlJBRDIxIikKCmBgYAoKIyMgWzIuMjddIE92ZXJsYXAgd2l0aCBTRT8KIyMjIyBRMS4gSG93IG1hbnkgU0VzIGFyZSBjb3ZlcmVkIHdpdGggTWljcm8tQyBsb29wcz8KYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmxvb3AgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpCmFuY2hvciA8LSBleHRyYWN0QW5jaG9yKGxvb3ApCgojIyMgV2h5dGUKbiA8LSBsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKGZpbmRPdmVybGFwcyhhbmNob3IsIHBlYWsuV2h5dGUuU0UpKSkpCnRvdGFsIDwtIGxlbmd0aChwZWFrLldoeXRlLlNFKQpjb3VudHMgPC0gYyhuLCB0b3RhbCAtIG4pCmxhYmVscyA8LSBwYXN0ZShjKCJjb3ZlcmVkIiwgIk5PVCBjb3ZlcmVkIiksIGNvdW50cykKcGllKGNvdW50cywgbGFiZWxzID0gbGFiZWxzLCAgbWFpbiA9IHBhc3RlMCgiV2h5dGUgU0UgY292ZXJhZ2UgXG4iLCB0b3RhbCksIGNvbCA9IGMoImdyZXkiLCAid2hpdGUiKSkKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAicGllX1NFX1doeXRlIikKd2lkdGggPC0gcGFuZWxTaXplKDQpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoNCkqbW1Ub0luY2gKIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgd2lkdGggPSB3aWR0aCwgaGVpZ2h0ID1oZWlnaHQpCiMgcGllKGNvdW50cywgbGFiZWxzID0gbGFiZWxzLCAgbWFpbiA9IHBhc3RlMCgiV2h5dGUgU0UgY292ZXJhZ2UgXG4iLCB0b3RhbCksIGNvbCA9IGMoImdyZXkiLCAid2hpdGUiKSwKIyAgICAgY2V4ID0gMSwgY2V4Lm1haW4gPSAxKQojIGRldi5vZmYoKQoKCgojIyMgRHlsYW4KbiA8LSBsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKGZpbmRPdmVybGFwcyhhbmNob3IsIHBlYWsuRHlsYW4uU0UpKSkpCnRvdGFsIDwtIGxlbmd0aChwZWFrLkR5bGFuLlNFKQpjb3VudHMgPC0gYyhuLCB0b3RhbCAtIG4pCmxhYmVscyA8LSBwYXN0ZShjKCJjb3ZlcmVkIiwgIk5PVCBjb3ZlcmVkIiksIGNvdW50cykKcGllKGNvdW50cywgbGFiZWxzID0gbGFiZWxzLCBtYWluID0gcGFzdGUwKCJEeWxhbiBTRSBjb3ZlcmFnZSBcbiIsIHRvdGFsKSwgY29sID0gYygiZ3JleSIsICJ3aGl0ZSIpKQoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsICJwaWVfU0VfTXVycGh5IikKd2lkdGggPC0gcGFuZWxTaXplKDQpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoNCkqbW1Ub0luY2gKIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgd2lkdGggPSB3aWR0aCwgaGVpZ2h0ID1oZWlnaHQpCiMgcGllKGNvdW50cywgbGFiZWxzID0gbGFiZWxzLCBtYWluID0gcGFzdGUwKCJNdXJwaHkgU0UgY292ZXJhZ2UgXG4iLCB0b3RhbCksIGNvbCA9IGMoImdyZXkiLCAid2hpdGUiKSkKIyAKIyBkZXYub2ZmKCkKCmBgYAojIyMjIFEyLiBGaXNoZXIncyBleGFjdCB0ZXN0PwojIyMjIyBkVEFHCmBgYHtyfQpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5Igpsb29wIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZS5iZWRwZSIpKQoKZ2V0T3ZlcmxhcExvb3BOdW0gPC0gZnVuY3Rpb24obG9vcCwgcGVhayl7CiAgYW5jaG9yMSA8LSBHUmFuZ2VzKHNlcW5hbWVzID0gbG9vcCRWMSwgcmFuZ2VzID0gSVJhbmdlcyhzdGFydCA9IGxvb3AkVjIsIGVuZCA9IGxvb3AkVjMpKQogIGFuY2hvcjIgPC0gR1JhbmdlcyhzZXFuYW1lcyA9IGxvb3AkVjQsIHJhbmdlcyA9IElSYW5nZXMoc3RhcnQgPSBsb29wJFY1LCBlbmQgPSBsb29wJFY2KSkKICBhIDwtIHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHMoYW5jaG9yMSwgcGVhaykpCiAgYiA8LSBxdWVyeUhpdHMoZmluZE92ZXJsYXBzKGFuY2hvcjIsIHBlYWspKQogIHJldHVybihsZW5ndGgodW5pcXVlKGMoYSwgYikpKSkKfQoKZ2V0U0VPdmVybGFwRmlzaGVyIDwtIGZ1bmN0aW9uKGFsbExvb3AsIHN1YnNldExvb3AsIHBlYWspewogIGFsbC5vdmVybGFwIDwtIGdldE92ZXJsYXBMb29wTnVtKGFsbExvb3AsIHBlYWspCiAgYWxsLm5vdE92ZXJsYXAgPC0gbnJvdyhhbGxMb29wKSAtIGFsbC5vdmVybGFwCiAgCiAgc3Vic2V0Lm92ZXJsYXAgPC0gZ2V0T3ZlcmxhcExvb3BOdW0oc3Vic2V0TG9vcCwgcGVhaykKICBzdWJzZXQubm90T3ZlcmxhcCA8LSBucm93KHN1YnNldExvb3ApIC0gc3Vic2V0Lm92ZXJsYXAKICAKICBjb250aW5nZW5jeV90YWJsZSA8LSBtYXRyaXgoYyhzdWJzZXQub3ZlcmxhcCwgc3Vic2V0Lm5vdE92ZXJsYXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLm92ZXJsYXAsIGFsbC5ub3RPdmVybGFwKSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkKICBjb2xuYW1lcyhjb250aW5nZW5jeV90YWJsZSkgPC0gYygiT3ZlcmxhcHBpbmciLCAiTm90X092ZXJsYXBwaW5nIikKICByb3duYW1lcyhjb250aW5nZW5jeV90YWJsZSkgPC0gYygiQWxsIGxvb3BzIiwgIlN1YnNldCBsb29wcyIpCiAgCiAgIyBQZXJmb3JtIEZpc2hlcidzIEV4YWN0IFRlc3QKICBmaXNoZXJfdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCiAgcmV0dXJuKGZpc2hlcl90ZXN0X3Jlc3VsdCkKfQoKCgpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmxvb3AudXBubyA8LSBiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQoKIyMjIER5bGFuCiMgU2VlZGluZwp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwbm8sIHBlYWsuRHlsYW4uU0UpCnJlc3VsdC50YiA8LSB0aWJibGUobG9vcFR5cGUgPSAiVVAvTk8iLAogICAgICAgICAgICAgICAgICAgIHRhcmdldCA9ICJEeWxhbiBTRSIsCiAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCgojIHRlbXAgPC0gZ2V0U0VPdmVybGFwRmlzaGVyKGxvb3AsIGxvb3AudXAsIHBlYWsuRHlsYW4uU0UpCiMgcmVzdWx0LnRiIDwtIHRpYmJsZShsb29wVHlwZSA9ICJVUCIsCiMgICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSAiRHlsYW4gU0UiLAojICAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAojICAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKIyBBZGQgcm93CiMgdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC5ubywgcGVhay5EeWxhbi5TRSkKIyByZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKIyAgIGFkZF9yb3cobG9vcFR5cGUgPSAiTk8iLAojICAgICAgICAgICB0YXJnZXQgPSAiRHlsYW4gU0UiLAojICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiMgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCgp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLmRvd24sIHBlYWsuRHlsYW4uU0UpCnJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogIGFkZF9yb3cobG9vcFR5cGUgPSAiRE9XTiIsCiAgICAgICAgICB0YXJnZXQgPSAiRHlsYW4gU0UiLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCiMjIyBXaHl0ZQojIFNlZWRpbmcKIyB0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwLCBwZWFrLldoeXRlLlNFKQojIHJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAojICAgYWRkX3Jvdyhsb29wVHlwZSA9ICJVUCIsCiMgICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSAiV2h5dGUgU0UiLAojICAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAojICAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCiMgQWRkIHJvdwp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwbm8sIHBlYWsuV2h5dGUuU0UpCnJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogIGFkZF9yb3cobG9vcFR5cGUgPSAiVVAvTk8iLAogICAgICAgICAgdGFyZ2V0ID0gIldoeXRlIFNFIiwKICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCgp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLmRvd24sIHBlYWsuV2h5dGUuU0UpCnJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogIGFkZF9yb3cobG9vcFR5cGUgPSAiRE9XTiIsCiAgICAgICAgICB0YXJnZXQgPSAiV2h5dGUgU0UiLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCgojIFZpc3VhbGl6YXRpb24KbGlicmFyeShjaXJjbGl6ZSkKZGF0YSA8LSByZXN1bHQudGIKaGVhdG1hcF9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBsb29wVHlwZSwgb2Rkc1JhdGlvKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGxvb3BUeXBlLCB2YWx1ZXNfZnJvbSA9IG9kZHNSYXRpbykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKcHZhbHVlX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGxvb3BUeXBlLCBwdmFsdWUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBsb29wVHlwZSwgdmFsdWVzX2Zyb20gPSBwdmFsdWUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoIiM0ODUyQTAiLCAid2hpdGUiLCAiI0NCMzMzQSIpKQoKcCA8LSBIZWF0bWFwKGFzLm1hdHJpeChoZWF0bWFwX2RhdGEpLAogICAgICAgIG5hbWUgPSAiT2RkcyBSYXRpbyIsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICAjIEFkZCBhbm5vdGF0aW9uIGZvciBwLXZhbHVlcwogICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgd2lkdGgsIGhlaWdodCwgZmlsbCkgewogICAgICAgICAgcHZhbCA8LSBwdmFsdWVfZGF0YVtpLCBqXQogICAgICAgICAgbGFiZWwgPC0gaWZlbHNlKHB2YWwgPiAwLjA1LCAibi5zLiIsIHNwcmludGYoIiUuMmUiLCBwdmFsKSkKICAgICAgICAgIGdyaWQudGV4dChsYWJlbCwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gZm9udFNpemVTLCBmb250ZmFtaWx5ID0gZm9udFR5cGUpKQogICAgICAgIH0sCiAgICAgICAgIyBDdXN0b21pemUgdGhlIGhlYXRtYXAgbGF5b3V0CiAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IGZvbnRTaXplUywgZm9udGZhbWlseSA9IGZvbnRUeXBlKSwKICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gZm9udFNpemVTLCBmb250ZmFtaWx5ID0gZm9udFR5cGUpLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCgKICAgICAgICAgIGF0ID0gYygwLCAxLCAyKSwKICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMSIsICIyIiksCiAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udGZhbWlseSA9IGZvbnRUeXBlLCBmb250c2l6ZSA9IGZvbnRTaXplUyksCiAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGZvbnRmYW1pbHkgPSBmb250VHlwZSwgZm9udHNpemUgPSBmb250U2l6ZVMpCiAgICAgICAgKQopCgojIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiaGVhdG1hcF9TRV9lbnJpY2htZW50IikKIyB3aWR0aCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaAojIGhlaWdodCA8LSBwYW5lbFNpemUoMC43KSptbVRvSW5jaAojIHN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPWhlaWdodCkKIyBwcmludChwKQojIGRldi5vZmYoKQojIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9aGVpZ2h0LCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iKQojIHByaW50KHApCiMgZGV2Lm9mZigpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZGF0YSRsb29wVHlwZSA8LSBmYWN0b3IoZGF0YSRsb29wVHlwZSwgbGV2ZWxzID0gYygiVVAvTk8iLCAiRE9XTiIpKQpkYXRhJHRhcmdldCA8LSBmYWN0b3IoZGF0YSR0YXJnZXQsIGxldmVscyA9IGMoIldoeXRlIFNFIiwgIkR5bGFuIFNFIikpCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGxvb3BUeXBlLCB5ID0gdGFyZ2V0LCBzaXplID0gLWxvZzEwKHB2YWx1ZSksIGZpbGwgPSBvZGRzUmF0aW8pKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCAgICAgICAgIyBFbnN1cmVzIGEgcG9pbnQgd2l0aCBhbiBvdXRsaW5lCiAgICAgICAgICAgICBzdHJva2UgPSAxKnB0VG9NTSAgICAgICMgTGluZSB3aWR0aCBmb3IgdGhlIGJvcmRlcgogICkgKyB0aGVtZV9idygpICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCAzKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiM0ODUyQTAiLCAid2hpdGUiLCAiI0NCMzMzQSIpLCAgIyBEZWZpbmUgZ3JhZGllbnQgY29sb3JzCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoYygwLjUsIDEsIDEuNSkpLCBsaW1pdHMgPSBjKDAuNSwgMS41KSwgCiAgICAgICAgICAgICAgICAgICAgICAjbG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDEsIDMpLAogICAgICAgICAgICAgICAgICAgICAgb29iID0gc2NhbGVzOjpzcXVpc2gsICMgRGVmaW5lIGdyYWRpZW50IGNvbG9ycwogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICMgQWRqdXN0IGhlaWdodCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICApCiAgKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApCgpmaWxlTmFtZSA8LSBoZXJlKGZpZ0RpciwgImhlYXRtYXBfU0VfZW5yaWNobWVudF9kb3RwbG90IikKd2lkdGggPC0gcGFuZWxTaXplKDEuOCkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjEpKm1tVG9JbmNoCiMgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiMgcHJpbnQocCkKIyBkZXYub2ZmKCkKc3ZnbGl0ZShwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIiksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKYGBgCiMjIyMjIEE0ODUKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmxvb3AgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpCgpnZXRPdmVybGFwTG9vcE51bSA8LSBmdW5jdGlvbihsb29wLCBwZWFrKXsKICBhbmNob3IxIDwtIEdSYW5nZXMoc2VxbmFtZXMgPSBsb29wJFYxLCByYW5nZXMgPSBJUmFuZ2VzKHN0YXJ0ID0gbG9vcCRWMiwgZW5kID0gbG9vcCRWMykpCiAgYW5jaG9yMiA8LSBHUmFuZ2VzKHNlcW5hbWVzID0gbG9vcCRWNCwgcmFuZ2VzID0gSVJhbmdlcyhzdGFydCA9IGxvb3AkVjUsIGVuZCA9IGxvb3AkVjYpKQogIGEgPC0gcXVlcnlIaXRzKGZpbmRPdmVybGFwcyhhbmNob3IxLCBwZWFrKSkKICBiIDwtIHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHMoYW5jaG9yMiwgcGVhaykpCiAgcmV0dXJuKGxlbmd0aCh1bmlxdWUoYyhhLCBiKSkpKQp9CgpnZXRTRU92ZXJsYXBGaXNoZXIgPC0gZnVuY3Rpb24oYWxsTG9vcCwgc3Vic2V0TG9vcCwgcGVhayl7CiAgYWxsLm92ZXJsYXAgPC0gZ2V0T3ZlcmxhcExvb3BOdW0oYWxsTG9vcCwgcGVhaykKICBhbGwubm90T3ZlcmxhcCA8LSBucm93KGFsbExvb3ApIC0gYWxsLm92ZXJsYXAKICAKICBzdWJzZXQub3ZlcmxhcCA8LSBnZXRPdmVybGFwTG9vcE51bShzdWJzZXRMb29wLCBwZWFrKQogIHN1YnNldC5ub3RPdmVybGFwIDwtIG5yb3coc3Vic2V0TG9vcCkgLSBzdWJzZXQub3ZlcmxhcAogIAogIGNvbnRpbmdlbmN5X3RhYmxlIDwtIG1hdHJpeChjKHN1YnNldC5vdmVybGFwLCBzdWJzZXQubm90T3ZlcmxhcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGwub3ZlcmxhcCwgYWxsLm5vdE92ZXJsYXApLCBucm93ID0gMiwgYnlyb3cgPSBUUlVFKQogIGNvbG5hbWVzKGNvbnRpbmdlbmN5X3RhYmxlKSA8LSBjKCJPdmVybGFwcGluZyIsICJOb3RfT3ZlcmxhcHBpbmciKQogIHJvd25hbWVzKGNvbnRpbmdlbmN5X3RhYmxlKSA8LSBjKCJBbGwgbG9vcHMiLCAiU3Vic2V0IGxvb3BzIikKICAKICAjIFBlcmZvcm0gRmlzaGVyJ3MgRXhhY3QgVGVzdAogIGZpc2hlcl90ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSkKICByZXR1cm4oZmlzaGVyX3Rlc3RfcmVzdWx0KQp9CgoKCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX0E0ODV2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQoKIyMjIER5bGFuCiMgU2VlZGluZwp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwLCBwZWFrLkR5bGFuLlNFKQpyZXN1bHQudGIgPC0gdGliYmxlKGxvb3BUeXBlID0gIlVQIiwKICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSAiRHlsYW4gU0UiLAogICAgICAgICAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQojIEFkZCByb3cKdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC5ubywgcGVhay5EeWxhbi5TRSkKcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgYWRkX3Jvdyhsb29wVHlwZSA9ICJOTyIsCiAgICAgICAgICB0YXJnZXQgPSAiRHlsYW4gU0UiLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCnRlbXAgPC0gZ2V0U0VPdmVybGFwRmlzaGVyKGxvb3AsIGxvb3AuZG93biwgcGVhay5EeWxhbi5TRSkKcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgYWRkX3Jvdyhsb29wVHlwZSA9ICJET1dOIiwKICAgICAgICAgIHRhcmdldCA9ICJEeWxhbiBTRSIsCiAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQoKIyMjIFdoeXRlCiMgU2VlZGluZwp0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwLCBwZWFrLldoeXRlLlNFKQpyZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICBhZGRfcm93KGxvb3BUeXBlID0gIlVQIiwKICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSAiV2h5dGUgU0UiLAogICAgICAgICAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQojIEFkZCByb3cKdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC5ubywgcGVhay5XaHl0ZS5TRSkKcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgYWRkX3Jvdyhsb29wVHlwZSA9ICJOTyIsCiAgICAgICAgICB0YXJnZXQgPSAiV2h5dGUgU0UiLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCnRlbXAgPC0gZ2V0U0VPdmVybGFwRmlzaGVyKGxvb3AsIGxvb3AuZG93biwgcGVhay5XaHl0ZS5TRSkKcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgCiAgYWRkX3Jvdyhsb29wVHlwZSA9ICJET1dOIiwKICAgICAgICAgIHRhcmdldCA9ICJXaHl0ZSBTRSIsCiAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICBvZGRzUmF0aW8gPSB0ZW1wJGVzdGltYXRlKQoKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGNpcmNsaXplKQpkYXRhIDwtIHJlc3VsdC50YgpoZWF0bWFwX2RhdGEgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIGxvb3BUeXBlLCBvZGRzUmF0aW8pICU+JQpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbG9vcFR5cGUsIHZhbHVlc19mcm9tID0gb2Rkc1JhdGlvKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgpwdmFsdWVfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgbG9vcFR5cGUsIHB2YWx1ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGxvb3BUeXBlLCB2YWx1ZXNfZnJvbSA9IHB2YWx1ZSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJ0YXJnZXQiKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgNSksIAogICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCkhlYXRtYXAoYXMubWF0cml4KGhlYXRtYXBfZGF0YSksCiAgICAgICAgbmFtZSA9ICJPZGRzIFJhdGlvIiwKICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICMgQWRkIGFubm90YXRpb24gZm9yIHAtdmFsdWVzCiAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBmaWxsKSB7CiAgICAgICAgICBwdmFsIDwtIHB2YWx1ZV9kYXRhW2ksIGpdCiAgICAgICAgICBsYWJlbCA8LSBpZmVsc2UocHZhbCA+IDAuMDUsICJuLnMuIiwgc3ByaW50ZigiJS4yZSIsIHB2YWwpKQogICAgICAgICAgZ3JpZC50ZXh0KGxhYmVsLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSAxMCkpCiAgICAgICAgfSwKICAgICAgICAjIEN1c3RvbWl6ZSB0aGUgaGVhdG1hcCBsYXlvdXQKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fdGl0bGUgPSAiSW50ZXJlc3QiLAogICAgICAgIHJvd190aXRsZSA9ICJUYXJnZXQiLAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChhdCA9IGMoMCwgMSwgMiwgMywgNCwgNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKSkKCgoKYGBgCgoKIyMgWzIuMjhdIENvbXBhcmluZyBkaWZmZXJlbnRpYWwgbG9vcHMgaW4gZFRBRyB0byBBNDg1ClRoZSBxdWVzdGlvbiBJIHdhbnQgdG8gYXNrIGhlcmUgaXMgd2hldGhlciBwZXJ0dXJiZWQgbG9vcHMgaW4gZFRBRyBleHBlcmltZW50cyBhcmUgZWl0aGVyIHBlcnR1cmJlZCBvciBub3QgcGVydHVyYmVkIGluIEE0ODUgZXhwZXJpbWVudC4gSWYgdGhlcmUgaXMgY29tcGVuc2F0aW9uIGdvaW5nIG9uIGJldHdlZW4gUkFEMjEgYW5kIEE0ODUsIFVQIGxvb3AgaW4gUkFEMjEgc2hvdWxkIGJlIG1vcmUgRE9XTiBpbiBBNDg1IGFuZCB2aWNlIHZlcnNhCiMjIyMgRXhwbG9yYXRvcnkgcGFydApgYGB7cn0KZGlmZkN1dG9mZiA8LSAwLjIKbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQpkYXRhIDwtIGRhdGEgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSkpCgogdGVtcCA8LSBkYXRhCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkZGlmZl9kVEFHX0RNU08sIHRlbXAkZGlmZl9BNDg1X0RNU08sIG4gPSAxMDApCiAgdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQogIAogIHAxIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGRpZmZfZFRBR19ETVNPLCB5ID0gZGlmZl9BNDg1X0RNU08sIGNvbG9yID0gZGVuc2l0eSkpICsKICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgYWxwaGEgPSAxLCBjb2xvciA9ICJibGFjayIpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBhbHBoYSA9IDEsIGNvbG9yID0gImJsYWNrIikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZGlmZkN1dG9mZiwgYWxwaGEgPSAxLCBjb2xvciA9ICJibGFjayIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1kaWZmQ3V0b2ZmLCBhbHBoYSA9IDEsIGNvbG9yID0gImJsYWNrIikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICtjb29yZF9maXhlZChyYXRpbyA9IDEsIHlsaW0gPSBjKC0xLCAxKSwgeGxpbSA9IGMoLTEsIDEpKSArIAogICAgdGhlbWVfY2xhc3NpYygpCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJzY2F0dGVycGxvdF8iLCBuYW1lLCAiXyIsIGRpZmZDdXRvZmYsICJfZGlmZl8iLCBsb29wTmFtZSwgIl9kVEFHLSIsIGRpZmZOYW1lKQogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzKQogIHByaW50KHAxKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIAogICAgICAgICAgd2lkdGggPSAzLjUsIGhlaWdodCA9IDMpCiAgcHJpbnQocDEpCiAgZGV2Lm9mZigpCgoKCmBgYAoKCiMjIyMgU2NhdHRlcnBsb3QgJiBib3ggcGxvdApgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQpkYXRhIDwtIGRhdGEgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSkpCgptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RkVEFHIDwtIGZ1bmN0aW9uKGRhdGEsIEFubm9MaXN0LCBkaWZmLCBuYW1lLCBsb29wTmFtZSwgZGlmZk5hbWUpewogIHRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIEFubm9MaXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cGRvd25fZFRBR19ETVNPICVpbiUgZGlmZikKICB0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRkaWZmX2RUQUdfRE1TTywgdGVtcCRkaWZmX0E0ODVfRE1TTywgbiA9IDEwMCkKICB0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCgogIHAxIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGRpZmZfZFRBR19ETVNPLCB5ID0gZGlmZl9BNDg1X0RNU08sIGNvbG9yID0gZGVuc2l0eSkpICsKICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArIAogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2wgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAtZGlmZkN1dG9mZiwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IGRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICtjb29yZF9maXhlZChyYXRpbyA9IDEsIHlsaW0gPSBjKC0xLCAxKSwgeGxpbSA9IGMoLTEsIDEpKSArIAogICAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShwYXN0ZTAobmFtZSwgIl8iLCBsb29wTmFtZSwgIl9kVEFHLSIsIGRpZmZOYW1lKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA1KSkKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNjYXR0ZXJwbG90XyIsIG5hbWUsICJfIiwgZGlmZkN1dG9mZiwgIl9kaWZmXyIsIGxvb3BOYW1lLCAiX2RUQUctIiwgZGlmZk5hbWUpCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAzLjUsIGhlaWdodCA9IDMpCiAgcHJpbnQocDEpCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgCiAgICAgICAgICB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMykKICBwcmludChwMSkKICBkZXYub2ZmKCkKfQoKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90ZFRBRyhkYXRhLCB1bmlxdWUoZGF0YSRBbm5vMiksIGMoIlVQIiwgIk5PIiwgIkRPV04iKSwgbmFtZSwgImFsbCIsICJhbGwiKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RkVEFHKGRhdGEsIHVuaXF1ZShkYXRhJEFubm8yKSwgYygiVVAiKSwgbmFtZSwgImFsbCIsICJVUCIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdGRUQUcoZGF0YSwgdW5pcXVlKGRhdGEkQW5ubzIpLCBjKCJOTyIpLCBuYW1lLCAiYWxsIiwgIk5PIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90ZFRBRyhkYXRhLCB1bmlxdWUoZGF0YSRBbm5vMiksIGMoIkRPV04iKSwgbmFtZSwgImFsbCIsICJET1dOIikKCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdGRUQUcoZGF0YSwgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgYygiVVAiLCAiTk8iLCAiRE9XTiIpLCBuYW1lLCAicGUtcGUiLCAiYWxsIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90ZFRBRyhkYXRhLCBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBjKCJVUCIpLCBuYW1lLCAicGUtcGUiLCAiVVAiKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RkVEFHKGRhdGEsIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIGMoIk5PIiksIG5hbWUsICJwZS1wZSIsICJOTyIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdGRUQUcoZGF0YSwgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgYygiRE9XTiIpLCBuYW1lLCAicGUtcGUiLCAiRE9XTiIpCgptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RkVEFHKGRhdGEsIGMoIlMtUyIsICJTLVgiKSwgYygiVVAiLCAiTk8iLCAiRE9XTiIpLCBuYW1lLCAic3RyIiwgImFsbCIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdGRUQUcoZGF0YSwgYygiUy1TIiwgIlMtWCIpLCBjKCJVUCIpLCBuYW1lLCAic3RyIiwgIlVQIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90ZFRBRyhkYXRhLCBjKCJTLVMiLCAiUy1YIiksIGMoIk5PIiksIG5hbWUsICJzdHIiLCAiTk8iKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RkVEFHKGRhdGEsIGMoIlMtUyIsICJTLVgiKSwgYygiRE9XTiIpLCBuYW1lLCAic3RyIiwgIkRPV04iKQoKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90QTQ4NSA8LSBmdW5jdGlvbihkYXRhLCBBbm5vTGlzdCwgZGlmZiwgbmFtZSwgbG9vcE5hbWUsIGRpZmZOYW1lKXsKICB0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBBbm5vTGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBkb3duX0E0ODVfRE1TTyAlaW4lIGRpZmYpCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkZGlmZl9kVEFHX0RNU08sIHRlbXAkZGlmZl9BNDg1X0RNU08sIG4gPSAxMDApCiAgdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQoKICBwMSA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBkaWZmX2RUQUdfRE1TTywgeSA9IGRpZmZfQTQ4NV9ETVNPLCBjb2xvciA9IGRlbnNpdHkpKSArCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKyAKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArY29vcmRfZml4ZWQocmF0aW8gPSAxLCB5bGltID0gYygtMSwgMSksIHhsaW0gPSBjKC0xLCAxKSkgKyAKICAgIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUocGFzdGUwKG5hbWUsICJfIiwgbG9vcE5hbWUsICJfQTQ4NUctIiwgZGlmZk5hbWUpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpKQogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgic2NhdHRlcnBsb3RfIiwgbmFtZSwgIl8iLCBkaWZmQ3V0b2ZmLCAiX2RpZmZfIiwgbG9vcE5hbWUsICJfQTQ4NS0iLCBkaWZmTmFtZSkKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMykKICBwcmludChwMSkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICAgIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzKQogIHByaW50KHAxKQogIGRldi5vZmYoKQp9CgptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RBNDg1KGRhdGEsIHVuaXF1ZShkYXRhJEFubm8yKSwgYygiVVAiLCAiTk8iLCAiRE9XTiIpLCBuYW1lLCAiYWxsIiwgImFsbCIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdEE0ODUoZGF0YSwgdW5pcXVlKGRhdGEkQW5ubzIpLCBjKCJVUCIpLCBuYW1lLCAiYWxsIiwgIlVQIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90QTQ4NShkYXRhLCB1bmlxdWUoZGF0YSRBbm5vMiksIGMoIk5PIiksIG5hbWUsICJhbGwiLCAiTk8iKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RBNDg1KGRhdGEsIHVuaXF1ZShkYXRhJEFubm8yKSwgYygiRE9XTiIpLCBuYW1lLCAiYWxsIiwgIkRPV04iKQoKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90QTQ4NShkYXRhLCBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBjKCJVUCIsICJOTyIsICJET1dOIiksIG5hbWUsICJwZS1wZSIsICJhbGwiKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RBNDg1KGRhdGEsIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIGMoIlVQIiksIG5hbWUsICJwZS1wZSIsICJVUCIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdEE0ODUoZGF0YSwgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgYygiTk8iKSwgbmFtZSwgInBlLXBlIiwgIk5PIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90QTQ4NShkYXRhLCBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpLCBjKCJET1dOIiksIG5hbWUsICJwZS1wZSIsICJET1dOIikKCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdEE0ODUoZGF0YSwgYygiUy1TIiwgIlMtWCIpLCBjKCJVUCIsICJOTyIsICJET1dOIiksIG5hbWUsICJzdHIiLCAiYWxsIikKbWFrZUFjcm9zc1NhbXBsZVNjYXR0ZXJwbG90QTQ4NShkYXRhLCBjKCJTLVMiLCAiUy1YIiksIGMoIlVQIiksIG5hbWUsICJzdHIiLCAiVVAiKQptYWtlQWNyb3NzU2FtcGxlU2NhdHRlcnBsb3RBNDg1KGRhdGEsIGMoIlMtUyIsICJTLVgiKSwgYygiTk8iKSwgbmFtZSwgInN0ciIsICJOTyIpCm1ha2VBY3Jvc3NTYW1wbGVTY2F0dGVycGxvdEE0ODUoZGF0YSwgYygiUy1TIiwgIlMtWCIpLCBjKCJET1dOIiksIG5hbWUsICJzdHIiLCAiRE9XTiIpCgojIyMjIyMjIyBCYXJwbG90CnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdCh1cGRvd25fZFRBR19ETVNPLCBkaWZmX0E0ODVfRE1TTykKZ2dwbG90KHRlbXAsIGFlcyh4ID0gdXBkb3duX2RUQUdfRE1TTywgeSA9IGRpZmZfQTQ4NV9ETVNPKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0wLjIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDAuNSkpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKSAlPiUgZHBseXI6OnNlbGVjdCh1cGRvd25fZFRBR19ETVNPLCBkaWZmX0E0ODVfRE1TTykgCmdncGxvdCh0ZW1wLCBhZXMoeCA9IHVwZG93bl9kVEFHX0RNU08sIHkgPSBkaWZmX0E0ODVfRE1TTykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtMC4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMC41LCAwLjUpKQoKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlMtUyIsICJTLVgiKSkgJT4lIGRwbHlyOjpzZWxlY3QodXBkb3duX2RUQUdfRE1TTywgZGlmZl9BNDg1X0RNU08pIApnZ3Bsb3QodGVtcCwgYWVzKHggPSB1cGRvd25fZFRBR19ETVNPLCB5ID0gZGlmZl9BNDg1X0RNU08pKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLTAuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuNSwgMC41KSkKCiMjIwp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodXBkb3duX0E0ODVfRE1TTywgZGlmZl9kVEFHX0RNU08pCmdncGxvdCh0ZW1wLCBhZXMoeCA9IHVwZG93bl9BNDg1X0RNU08sIHkgPSBkaWZmX2RUQUdfRE1TTykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtMC4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMC41LCAwLjUpKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJFLUUiKSkgJT4lIGRwbHlyOjo6c2VsZWN0KHVwZG93bl9BNDg1X0RNU08sIGRpZmZfZFRBR19ETVNPKQpnZ3Bsb3QodGVtcCwgYWVzKHggPSB1cGRvd25fQTQ4NV9ETVNPLCB5ID0gZGlmZl9kVEFHX0RNU08pKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLTAuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuNSwgMC41KSkKCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJTLVMiLCAiUy1YIikpICU+JSBkcGx5cjo6OnNlbGVjdCh1cGRvd25fQTQ4NV9ETVNPLCBkaWZmX2RUQUdfRE1TTykKZ2dwbG90KHRlbXAsIGFlcyh4ID0gdXBkb3duX0E0ODVfRE1TTywgeSA9IGRpZmZfZFRBR19ETVNPKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0wLjIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDAuNSkpCgpgYGAKCiMjIFsyLjI5XSBDb21wYXJ0bWVudCBhbmFseXNpcwpRLiBXaGF0IGFyZSB0aGUgY2hhbmdlcyBpbiBjb21wYXJ0bWVudCBsZXZlbCB1cG9uIEE0ODUgdHJlYXRtZW50PwojIyMjIENvbXBhcnRtZW50IGNoYW5nZSBkaXN0cmlidXRpb24KYGBge3J9CiMjIyBJTVBPUlRJTkcgQ09NUEFSTVRORVQgU0NPUkVTCmNvbXBEaXIgPC0gaGVyZSgiLi4vLi4iLCAicmVzdWx0IiwgImNvbXBhcnRtZW50IiwgIkNzY29yZVRvb2xzIikKCmNzY29yZS5ETVNPIDwtIGFzX3RpYmJsZShmcmVhZChoZXJlKGNvbXBEaXIsICJHMURNU09fTWVyZ2VkXzEwa2JfY3Njb3JlX2ZpbmFsLmJlZGdyYXBoIiksIHNraXAgPSAxKSkgJT4lCiAgZHBseXI6Om11dGF0ZShWMiA9IFYyICsgMSkKY29sbmFtZXMoY3Njb3JlLkRNU08pIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiLCAiY3Njb3JlX0RNU08iKQoKY3Njb3JlLkE0ODUgPC0gYXNfdGliYmxlKGZyZWFkKGhlcmUoY29tcERpciwgIkcxQTQ4NV9NZXJnZWRfMTBrYl9jc2NvcmVfZmluYWwuYmVkZ3JhcGgiKSwgc2tpcCA9IDEpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFYyID0gVjIgKyAxKQpjb2xuYW1lcyhjc2NvcmUuQTQ4NSkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJjc2NvcmVfQTQ4NSIpCgoKY3Njb3JlIDwtIGRwbHlyOjpmdWxsX2pvaW4oY3Njb3JlLkRNU08sIGNzY29yZS5BNDg1LCBieSA9IGMoImNociIsICJzdGFydCIsICJlbmQiKSkKCiMgRklMVEVSIFJPV1MgV0lUSCBOQQpjc2NvcmUgPC0gY3Njb3JlICU+JSBmaWx0ZXIoIWlmX2FueShldmVyeXRoaW5nKCksIGlzLm5hKSkKCiMgQW5ub3RhdGluZyBob3cgdGhlIGNvbXBhcnRtZW50IGNoYW5nZWQKdGhyZXNob2xkIDwtIDAuMQpjc2NvcmUgPC0gY3Njb3JlICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoaXNBQl9ETVNPID0gaWZlbHNlKGNzY29yZV9ETVNPID4gMCwgIkEiLCAiQiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNBQl9BNDg1ID0gaWZlbHNlKGNzY29yZV9BNDg1ID4gMCwgIkEiLCAiQiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hhbmdlVHlwZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJzKGNzY29yZV9ETVNPIC0gY3Njb3JlX0E0ODUpIDwgdGhyZXNob2xkIH4gIlVuY2hhbmdlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzQUJfRE1TTyA9PSAiQSIgJiBpc0FCX0E0ODUgPT0gIkIiIH4gIkF0b0IiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc0FCX0RNU08gPT0gIkIiICYgaXNBQl9BNDg1ID09ICJBIiB+ICJCdG9BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNBQl9ETVNPID09ICJBIiAmIGlzQUJfQTQ4NSA9PSAiQSIgJiBhYnMoY3Njb3JlX0RNU08pID4gYWJzKGNzY29yZV9BNDg1KSB+ICJBX3dlYWtlbmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzQUJfRE1TTyA9PSAiQSIgJiBpc0FCX0E0ODUgPT0gIkEiICYgYWJzKGNzY29yZV9ETVNPKSA8PSBhYnMoY3Njb3JlX0E0ODUpIH4gIkFfc3RyZW5ndGhlbmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzQUJfRE1TTyA9PSAiQiIgJiBpc0FCX0E0ODUgPT0gIkIiICYgYWJzKGNzY29yZV9ETVNPKSA+IGFicyhjc2NvcmVfQTQ4NSkgfiAiQl93ZWFrZW5pbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc0FCX0RNU08gPT0gIkIiICYgaXNBQl9BNDg1ID09ICJCIiAmIGFicyhjc2NvcmVfRE1TTykgPD0gYWJzKGNzY29yZV9BNDg1KSB+ICJCX3N0cmVuZ3RoZW5pbmciICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCmNzY29yZV9zdW1tYXJ5IDwtIHRpYmJsZShjb21wYXJpc29uID0gcmVwKCJBNDg1X3ZzX0RNU08iLCA3KSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZVR5cGUgPSBjKCJBdG9CIiwgIkJ0b0EiLCAiQV93ZWFrZW5pbmciLCAiQV9zdHJlbmd0aGVuaW5nIiwgIkJfd2Vha2VuaW5nIiwgIkJfc3RyZW5ndGhlbmluZyIsICJVbmNoYW5nZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYyhzdW0oY3Njb3JlJGNoYW5nZVR5cGUgPT0gIkF0b0IiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0oY3Njb3JlJGNoYW5nZVR5cGUgPT0gIkJ0b0EiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0oY3Njb3JlJGNoYW5nZVR5cGUgPT0gIkFfd2Vha2VuaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtKGNzY29yZSRjaGFuZ2VUeXBlID09ICJBX3N0cmVuZ3RoZW5pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0oY3Njb3JlJGNoYW5nZVR5cGUgPT0gIkJfd2Vha2VuaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtKGNzY29yZSRjaGFuZ2VUeXBlID09ICJCX3N0cmVuZ3RoZW5pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0oY3Njb3JlJGNoYW5nZVR5cGUgPT0gIlVuY2hhbmdlZCIpKSkKY3Njb3JlX3N1bW1hcnkkY2hhbmdlVHlwZSA8LSBmYWN0b3IoY3Njb3JlX3N1bW1hcnkkY2hhbmdlVHlwZSwgbGV2ZWxzID0gYygiQV93ZWFrZW5pbmciLCAiQXRvQiIsICJCX3N0cmVuZ3RoZW5pbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCX3dlYWtlbmluZyIsICJCdG9BIiwgIkFfc3RyZW5ndGhlbmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVuY2hhbmdlZCIpKQpnZ3Bsb3QoY3Njb3JlX3N1bW1hcnksIGFlcyh4ID0gY29tcGFyaXNvbiwgeSA9IHZhbHVlLCBmaWxsID0gY2hhbmdlVHlwZSkpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNreWJsdWUiLCAiYmx1ZSIsICJkYXJrYmx1ZSIsICJwaW5rIiwgInJlZDIiLCAiZGFya3JlZCIgLCJncmV5IikpCiAgCmBgYAojIyMjIENvbWJpbmluZyB3aXRoIFJOQS1zZXEKYGBge3J9CmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1MsIFY2KQpjb2xuYW1lcyhnZW5lLnRiKSA8LSBjKCJjaHIiLCAiVFNTIiwgImVuc2VtYmwiKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLkE0ODUuc2VsZWN0ZWQyX0cxLjJpLkE0ODVfdnNfRzEuMmkuRE1TTy50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGxvZzJGb2xkQ2hhbmdlLCBzaHJpbmtlZF9sb2cyRkMsIHBhZGosIGV4dGVybmFsX2dlbmVfbmFtZSkKZGlmZi5STkEgPC0gZGlmZi5STkEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oZ2VuZS50YiwgYnkgPSBjKCJlbnNlbWJsX2dlbmVfaWQiID0gImVuc2VtYmwiKSkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoVFNTKSkKCmFscGhhIDwtIDAuMDUKZmNDdXRvZmYgPC0gMC41CgpkaWZmLlJOQSA8LSBkaWZmLlJOQSAlPiUgZHBseXI6Om11dGF0ZShkaWZmID0gY2FzZV93aGVuKHBhZGogPCBhbHBoYSAmIHNocmlua2VkX2xvZzJGQyA+IGZjQ3V0b2ZmIH4gIlVQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWRqIDwgYWxwaGEgJiBzaHJpbmtlZF9sb2cyRkMgPCAtZmNDdXRvZmYgfiAiRE9XTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOTyIpKQoKCmdldENvbXBDaGFuZ2VUeXBlIDwtIGZ1bmN0aW9uKGNocm9tLCBUU1MsIGNzY29yZS50Yil7CiAgdGVtcC50YiA8LSBjc2NvcmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoY2hyID09IGNocm9tLCBzdGFydCA8IFRTUywgZW5kID4gVFNTKQogIG91dCA8LSB0ZW1wLnRiJGNoYW5nZVR5cGUKICBpZihsZW5ndGgob3V0KSA8IDEpewogICAgcmV0dXJuKE5BKQogIH1lbHNlewogICAgcmV0dXJuKG91dCkKICB9Cn0KCmNzY29yZS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoY3Njb3JlWzE6M10pCnRlbXAgPC1kaWZmLlJOQSAlPiUgZHBseXI6Om11dGF0ZShzdGFydCA9IFRTUywgZW5kID0gVFNTICsxKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCkKZGlmZi5STkEuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCm92ZXJsYXAgPC0gZmluZE92ZXJsYXBzKGRpZmYuUk5BLmdyLCBjc2NvcmUuZ3IpCgojY3Njb3JlLnNlbGVjdGVkIDwtIGNzY29yZSAlPiUgZHBseXI6OnNsaWNlKHN1YmplY3RIaXRzKG92ZXJsYXApKQojIyBQcm9ibGVtIG9mIGNlcnRhaW4gZ2VuZXMgbm90IGdldHRpbmcgb3ZlcmxhcCB3aXRoIGNzY29yZSBkdWUgdG8gc3BhcnNlIGNhbGxpbmc/CmJhdGNoMSA8LSBiaW5kX2NvbHMoZGlmZi5STkFbcXVlcnlIaXRzKG92ZXJsYXApXSwKICAgICAgICAgIGRhdGEudGFibGUoY3Njb3JlKVtzdWJqZWN0SGl0cyhvdmVybGFwKV0pCgoKbWlzc2VkIDwtIGRpZmYuUk5BWy1xdWVyeUhpdHMob3ZlcmxhcCldCnRlbXAgPC0gbWlzc2VkICU+JSBkcGx5cjo6bXV0YXRlKFRTUyA9IFRTUyArIDEwMDAwKSAlPiUgZHBseXI6Om11dGF0ZShzdGFydCA9IFRTUywgZW5kID0gVFNTICsxKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCkKbWlzc2VkLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0ZW1wKQpvdmVybGFwIDwtIGZpbmRPdmVybGFwcyhtaXNzZWQuZ3IsIGNzY29yZS5ncikKYmF0Y2gyIDwtIGJpbmRfY29scyhtaXNzZWRbcXVlcnlIaXRzKG92ZXJsYXApXSwKICAgICAgICAgICAgICAgICAgICBkYXRhLnRhYmxlKGNzY29yZSlbc3ViamVjdEhpdHMob3ZlcmxhcCldKQoKbWlzc2VkMiA8LSBtaXNzZWRbLXF1ZXJ5SGl0cyhvdmVybGFwKV0KdGVtcCA8LSBtaXNzZWQyICU+JSBkcGx5cjo6bXV0YXRlKFRTUyA9IFRTUyAtIDEwMDAwKSAlPiUgZHBseXI6Om11dGF0ZShzdGFydCA9IFRTUywgZW5kID0gVFNTICsxKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCkKbWlzc2VkLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0ZW1wKQpvdmVybGFwIDwtIGZpbmRPdmVybGFwcyhtaXNzZWQuZ3IsIGNzY29yZS5ncikKYmF0Y2gzIDwtIGJpbmRfY29scyhtaXNzZWQyW3F1ZXJ5SGl0cyhvdmVybGFwKV0sCiAgICAgICAgICAgICAgICAgICAgZGF0YS50YWJsZShjc2NvcmUpW3N1YmplY3RIaXRzKG92ZXJsYXApXSkKCiNtaXNzZWQzIDwtIG1pc3NlZDJbLXF1ZXJ5SGl0cyhvdmVybGFwKV0KCgpkaWZmLlJOQSA8LSBiaW5kX3Jvd3MoYmF0Y2gxLCBiYXRjaDIsIGJhdGNoMykKCgojIFZJU1VBTElaRQpkaWZmLlJOQSRjaGFuZ2VUeXBlIDwtIGZhY3RvcihkaWZmLlJOQSRjaGFuZ2VUeXBlLCBsZXZlbHMgPSBjKCJBX3dlYWtlbmluZyIsICJBdG9CIiwgIkJfc3RyZW5ndGhlbmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJfd2Vha2VuaW5nIiwgIkJ0b0EiLCAiQV9zdHJlbmd0aGVuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVW5jaGFuZ2VkIikpCmdncGxvdChkaWZmLlJOQSwgYWVzKHggPSBkaWZmLCBmaWxsID0gY2hhbmdlVHlwZSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnModGl0bGUgPSAiU3RhY2tlZCBCYXIgUGxvdCBvZiBDaGFuZ2UgVHlwZSBieSBEaWZmIiwKICAgICAgIHggPSAiRGlmZiIsCiAgICAgICB5ID0gIkNvdW50IikgKwogIHRoZW1lX2J3KCkgKyAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2t5Ymx1ZSIsICJibHVlIiwgImRhcmtibHVlIiwgInBpbmsiLCAicmVkMiIsICJkYXJrcmVkIiAsImdyZXkiKSkKCgoKYGBgCiMjIyMgQ29tYmluaW5nIHdpdGggbG9vcApgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKCiMgVVAgbG9vcApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwIDwtIChleHRyYWN0QW5jaG9yKGxvb3AudXApKQphbmNob3IudXAudGIgPC0gYXNfdGliYmxlKGFuY2hvci51cCkgJT4lCiAgZHBseXI6Om11dGF0ZShjZW50ZXIgPSAoc3RhcnQgKyBlbmQpLzIpICU+JQogIGRwbHlyOjptdXRhdGUoc3RhcnQgPSBjZW50ZXItMSwgZW5kID0gY2VudGVyKzEpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2VxbmFtZXMsIHN0YXJ0LCBlbmQpCmFuY2hvci51cCA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoYW5jaG9yLnVwLnRiKQojIE5PIGxvb3AKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfQTQ4NXZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5ubyA8LSAoZXh0cmFjdEFuY2hvcihsb29wLm5vKSkKYW5jaG9yLm5vLnRiIDwtIGFzX3RpYmJsZShhbmNob3Iubm8pICU+JQogIGRwbHlyOjptdXRhdGUoY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yKSAlPiUKICBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gY2VudGVyLTEsIGVuZCA9IGNlbnRlcisxKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcW5hbWVzLCBzdGFydCwgZW5kKQphbmNob3Iubm8gPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGFuY2hvci5uby50YikKIyBET1dOIGxvb3AKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSAoZXh0cmFjdEFuY2hvcihsb29wLmRvd24pKQphbmNob3IuZG93bi50YiA8LSBhc190aWJibGUoYW5jaG9yLmRvd24pICU+JQogIGRwbHlyOjptdXRhdGUoY2VudGVyID0gKHN0YXJ0ICsgZW5kKS8yKSAlPiUKICBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gY2VudGVyLTEsIGVuZCA9IGNlbnRlcisxKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcW5hbWVzLCBzdGFydCwgZW5kKQphbmNob3IuZG93biA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoYW5jaG9yLmRvd24udGIpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyBPdmVybGFwCmNzY29yZS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoY3Njb3JlWzE6M10pCm92ZXJsYXAgPC0gZmluZE92ZXJsYXBzKGFuY2hvci51cCwgY3Njb3JlLmdyKQoKIyMgUHJvYmxlbSBvZiBjZXJ0YWluIGdlbmVzIG5vdCBnZXR0aW5nIG92ZXJsYXAgd2l0aCBjc2NvcmUgZHVlIHRvIHNwYXJzZSBjYWxsaW5nPwpiYXRjaDEgPC0gYmluZF9jb2xzKGRhdGEudGFibGUoYW5jaG9yLnVwLnRiKVtxdWVyeUhpdHMob3ZlcmxhcCldLAogICAgICAgICAgZGF0YS50YWJsZShjc2NvcmUpW3N1YmplY3RIaXRzKG92ZXJsYXApXSkKCgptaXNzZWQgPC0gZGF0YS50YWJsZShhbmNob3IudXAudGIpWy1xdWVyeUhpdHMob3ZlcmxhcCldCnRlbXAgPC0gbWlzc2VkICU+JSBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gc3RhcnQgLSAxMDAwMCwgZW5kID0gZW5kIC0gMTAwMDApICU+JQogIGRwbHlyOjpzZWxlY3Qoc2VxbmFtZXMsIHN0YXJ0LCBlbmQpCm1pc3NlZC5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCkKb3ZlcmxhcCA8LSBmaW5kT3ZlcmxhcHMobWlzc2VkLmdyLCBjc2NvcmUuZ3IpCmJhdGNoMiA8LSBiaW5kX2NvbHMoKG1pc3NlZClbcXVlcnlIaXRzKG92ZXJsYXApXSwKICAgICAgICAgIGRhdGEudGFibGUoY3Njb3JlKVtzdWJqZWN0SGl0cyhvdmVybGFwKV0pCgoKZGF0YS51cCA8LSBiaW5kX3Jvd3MoYmF0Y2gxLCBiYXRjaDIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIE92ZXJsYXAKY3Njb3JlLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShjc2NvcmVbMTozXSkKb3ZlcmxhcCA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLm5vLCBjc2NvcmUuZ3IpCgojIyBQcm9ibGVtIG9mIGNlcnRhaW4gZ2VuZXMgbm90IGdldHRpbmcgb3ZlcmxhcCB3aXRoIGNzY29yZSBkdWUgdG8gc3BhcnNlIGNhbGxpbmc/CmJhdGNoMSA8LSBiaW5kX2NvbHMoZGF0YS50YWJsZShhbmNob3Iubm8udGIpW3F1ZXJ5SGl0cyhvdmVybGFwKV0sCiAgICAgICAgICBkYXRhLnRhYmxlKGNzY29yZSlbc3ViamVjdEhpdHMob3ZlcmxhcCldKQoKCm1pc3NlZCA8LSBkYXRhLnRhYmxlKGFuY2hvci5uby50YilbLXF1ZXJ5SGl0cyhvdmVybGFwKV0KdGVtcCA8LSBtaXNzZWQgJT4lIGRwbHlyOjptdXRhdGUoc3RhcnQgPSBzdGFydCAtIDEwMDAwLCBlbmQgPSBlbmQgLSAxMDAwMCkgJT4lCiAgZHBseXI6OnNlbGVjdChzZXFuYW1lcywgc3RhcnQsIGVuZCkKbWlzc2VkLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0ZW1wKQpvdmVybGFwIDwtIGZpbmRPdmVybGFwcyhtaXNzZWQuZ3IsIGNzY29yZS5ncikKYmF0Y2gyIDwtIGJpbmRfY29scygobWlzc2VkKVtxdWVyeUhpdHMob3ZlcmxhcCldLAogICAgICAgICAgZGF0YS50YWJsZShjc2NvcmUpW3N1YmplY3RIaXRzKG92ZXJsYXApXSkKCgpkYXRhLm5vIDwtIGJpbmRfcm93cyhiYXRjaDEsIGJhdGNoMikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMgT3ZlcmxhcApjc2NvcmUuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGNzY29yZVsxOjNdKQpvdmVybGFwIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuZG93biwgY3Njb3JlLmdyKQoKIyMgUHJvYmxlbSBvZiBjZXJ0YWluIGdlbmVzIG5vdCBnZXR0aW5nIG92ZXJsYXAgd2l0aCBjc2NvcmUgZHVlIHRvIHNwYXJzZSBjYWxsaW5nPwpiYXRjaDEgPC0gYmluZF9jb2xzKGRhdGEudGFibGUoYW5jaG9yLmRvd24udGIpW3F1ZXJ5SGl0cyhvdmVybGFwKV0sCiAgICAgICAgICBkYXRhLnRhYmxlKGNzY29yZSlbc3ViamVjdEhpdHMob3ZlcmxhcCldKQoKCm1pc3NlZCA8LSBkYXRhLnRhYmxlKGFuY2hvci5kb3duLnRiKVstcXVlcnlIaXRzKG92ZXJsYXApXQp0ZW1wIDwtIG1pc3NlZCAlPiUgZHBseXI6Om11dGF0ZShzdGFydCA9IHN0YXJ0IC0gMTAwMDAsIGVuZCA9IGVuZCAtIDEwMDAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlcW5hbWVzLCBzdGFydCwgZW5kKQptaXNzZWQuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCm92ZXJsYXAgPC0gZmluZE92ZXJsYXBzKG1pc3NlZC5nciwgY3Njb3JlLmdyKQpiYXRjaDIgPC0gYmluZF9jb2xzKChtaXNzZWQpW3F1ZXJ5SGl0cyhvdmVybGFwKV0sCiAgICAgICAgICBkYXRhLnRhYmxlKGNzY29yZSlbc3ViamVjdEhpdHMob3ZlcmxhcCldKQoKCmRhdGEuZG93biA8LSBiaW5kX3Jvd3MoYmF0Y2gxLCBiYXRjaDIpCgpuLnVwIDwtIG5yb3coZGF0YS51cCkKbi5ubyA8LSBucm93KGRhdGEubm8pCm4uZG93biA8LSBucm93KGRhdGEuZG93bikKCmRhdGEgPC0gdGliYmxlKGxvb3BEaWZmID0gYyhyZXAoIlVQIiwgbi51cCksIHJlcCgiTk8iLCBuLm5vKSwgcmVwKCJET1dOIiwgbi5kb3duKSksCiAgICAgICAgICAgICAgY2hhbmdlVHlwZSA9IGMoZGF0YS51cCRjaGFuZ2VUeXBlLCBkYXRhLm5vJGNoYW5nZVR5cGUsIGRhdGEuZG93biRjaGFuZ2VUeXBlKSkKCiMgVklTVUFMSVpFCmRhdGEkY2hhbmdlVHlwZSA8LSBmYWN0b3IoZGF0YSRjaGFuZ2VUeXBlLCBsZXZlbHMgPSBjKCJBX3dlYWtlbmluZyIsICJBdG9CIiwgIkJfc3RyZW5ndGhlbmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJfd2Vha2VuaW5nIiwgIkJ0b0EiLCAiQV9zdHJlbmd0aGVuaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVW5jaGFuZ2VkIikpCmdncGxvdChkYXRhLCBhZXMoeCA9IGxvb3BEaWZmLCBmaWxsID0gY2hhbmdlVHlwZSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnModGl0bGUgPSAiU3RhY2tlZCBCYXIgUGxvdCBvZiBDaGFuZ2UgVHlwZSBieSBEaWZmIiwKICAgICAgIHggPSAiRGlmZiIsCiAgICAgICB5ID0gIkNvdW50IikgKwogIHRoZW1lX2J3KCkgKyAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2t5Ymx1ZSIsICJibHVlIiwgImRhcmtibHVlIiwgInBpbmsiLCAicmVkMiIsICJkYXJrcmVkIiAsImdyZXkiKSkKCgoKCmBgYAojIyBbMi4zMF0gQ2hyb21ITU0KYGBge3J9CnJlc3VsdERpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQiKQoKZGF0YSA8LSBmcmVhZChoZXJlKHJlc3VsdERpciwgImNocm9tSE1NIiwgIkE0ODVfcGUtcGVfYW5jaG9ycyIsICJvdmVybGFwX2VucmljaF8xMDBfc3RhdGUudHh0IikpCmNvbG5hbWVzKGRhdGEpIDwtIGMoInN0YXRlIiwgImdlbm9tZSIsICJwZS1wZV9BNDg1X2Rvd24iLCAicGUtcGVfQTQ4NV9ubyIsICJwZS1wZV9BNDg1X3VwIikKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KC1nZW5vbWUpCgpkYXRhX21hdHJpeCA8LSBkYXRhICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAic3RhdGUiKSAlPiUKICBhcy5tYXRyaXgoKQoKbGlicmFyeShjaXJjbGl6ZSkKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDEwKSwgCiAgICAgICAgICAgICAgICAgICAgICBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQoKSGVhdG1hcCgKICBkYXRhX21hdHJpeCwKICBuYW1lID0gIlZhbHVlIiwKICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsCiAgc2hvd19jb2x1bW5fbmFtZXMgPSBUUlVFLAogIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICBjb2wgPSBjb2xfZnVuCikKCiMjIyMjIyMKZGF0YTIgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDQpKQpkYXRhMiA8LSBkYXRhMiAlPiUgZHBseXI6OmZpbHRlcihgcGUtcGVfQTQ4NV9kb3duYCA+IGBwZS1wZV9BNDg1X3VwYCkKZGF0YV9tYXRyaXggPC0gZGF0YTIgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzdGF0ZSIpICU+JQogIGFzLm1hdHJpeCgpCgpsaWJyYXJ5KGNpcmNsaXplKQoKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMCwgMSwgMTApLCAKICAgICAgICAgICAgICAgICAgICAgIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpIZWF0bWFwKAogIGRhdGFfbWF0cml4LAogIG5hbWUgPSAiVmFsdWUiLAogIHNob3dfcm93X25hbWVzID0gVFJVRSwKICBzaG93X2NvbHVtbl9uYW1lcyA9IFRSVUUsCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgIGNvbCA9IGNvbF9mdW4KKQoKCmBgYAoKIyMgWzIuMzFdIE1ha2luZyBWaXN1YWxpemF0aW9uIEVhc3kKaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jvb2tzL2RldmVsL09IQ0EvcGFnZXMvdmlzdWFsaXphdGlvbi5odG1sCmBgYHtyfQojIyMgR2V0dGluZyBsb29wIElECnRlbXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpICU+JQogIGRwbHlyOjptdXRhdGUocmVzID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIHJlcywgVjIsIFY1LCBzZXAgPSAiXyIpKQpyZWdJRCA8LSB0ZW1wJGlkCgp0ZW1wIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmUuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShyZXMgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgcmVzLCBWMiwgVjUsIHNlcCA9ICJfIikpCnN0cklEIDwtIHRlbXAkaWQKCiMjIyMjIyMjIyMjIyMjIFJFRwojIyBGaWx0ZXJpbmcgbG9vcHMgdG8gcGxvdApkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfc2NvcmUudHN2IikpCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIHJlZ0lELCBkVEFHID4gMC41KSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhkVEFHKSkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6c2VsZWN0KHNlcSgxLCA2KSkKY29sbmFtZXModGVtcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQpsb29wcyA8LSBpbXBvcnRCZWRwZSh0ZW1wKQoKIyBWaXN1YWxpemF0aW9uCmhpY0RpciA8LSAiL1ZvbHVtZXMvVUtKSU5fU1NEL2RhdGFfdmF1bHRfMjAyNHN1bW1lcl9taWNyb0MvaGljIgp3aW5kb3dTaXplIDwtIDEqMWU2CgppID0gMQojIGZvcihpIGluIHNlcSgxLCAyNSkpewogICMjIExvYWRpbmcgaGljIGFuZCBwbG90dGluZwogIGNociA8LSBhc190aWJibGUobG9vcHNbaV0pJHNlcW5hbWVzMQogIGNlbnRlciA8LSAoYXNfdGliYmxlKGxvb3BzW2ldKSRzdGFydDEgKyBhc190aWJibGUobG9vcHNbaV0pJGVuZDIpLzIKICBzdGFydCA8LSBmbG9vcihjZW50ZXIgLSAwLjUqd2luZG93U2l6ZSkKICBlbmQgPC0gZmxvb3IoY2VudGVyICsgMC41KndpbmRvd1NpemUpCiAgCiAgY2YuRzFETVNPIDwtIEhpY0ZpbGUocGF0aCA9IGhlcmUoaGljRGlyLCAiRzEuRE1TTy5NZXJnZWQuaGljIikpCiAgY2YuRzFkVEFHIDwtIEhpY0ZpbGUocGF0aCA9IGhlcmUoaGljRGlyLCAiRzEuZFRBRy5NZXJnZWQuaGljIikpCiAgI2NmLkcxZFRBRyA8LSBIaWNGaWxlKHBhdGggPSBoZXJlKGhpY0RpciwgIkcxLkE0ODUuTWVyZ2VkLmhpYyIpKQoKICByZXMgPC0gMTAqMTAwMAogIHptYXggPC0gMi41CiAgaGljMSA8LSBpbXBvcnQoY2YuRzFETVNPLCBmb2N1cyA9IHBhc3RlMChjaHIsICI6Iiwgc3RhcnQsICItIiwgZW5kKSwgcmVzb2x1dGlvbiA9IHJlcykKICBoaWMyIDwtIGltcG9ydChjZi5HMWRUQUcsIGZvY3VzID0gcGFzdGUwKGNociwgIjoiLCBzdGFydCwgIi0iLCBlbmQpLCByZXNvbHV0aW9uID0gcmVzKQogIHAxIDwtIHBsb3RNYXRyaXgoaGljMSwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIHAyIDwtIHBsb3RNYXRyaXgoaGljMiwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIAogIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCBwYXN0ZTAoInZpc3V6bGlhdGlvbl9yZWdMb29wX2RUQUdfIiwgaSwgIl8xMGtiX2ZpZ3VyZVZlciIpKQogIAogIHdpZHRoIDwtIHBhbmVsU2l6ZSgyMCkqbW1Ub0luY2gKICBoZWlnaHQgPC0gcGFuZWxTaXplKDEwKSptbVRvSW5jaAogIAogIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQpCiAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgYWxpZ24gPSAiaCIpKQogIGRldi5vZmYoKQogIHN2Z2xpdGUocGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQpCiAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgYWxpZ24gPSAiaCIpKQogIGRldi5vZmYoKQogIAogIHJlcyA8LSAyNSoxMDAwCiAgem1heCA8LSAzCiAgc3RhcnQgPC0gZmxvb3IoY2VudGVyIC0gd2luZG93U2l6ZSkKICBlbmQgPC0gZmxvb3IoY2VudGVyICsgd2luZG93U2l6ZSkKICBoaWMxIDwtIGltcG9ydChjZi5HMURNU08sIGZvY3VzID0gcGFzdGUwKGNociwgIjoiLCBzdGFydCwgIi0iLCBlbmQpLCByZXNvbHV0aW9uID0gcmVzKQogIGhpYzIgPC0gaW1wb3J0KGNmLkcxZFRBRywgZm9jdXMgPSBwYXN0ZTAoY2hyLCAiOiIsIHN0YXJ0LCAiLSIsIGVuZCksIHJlc29sdXRpb24gPSByZXMpCiAgcDEgPC0gcGxvdE1hdHJpeChoaWMxLCBkcGkgPSAxMDAwLCBsaW1pdHMgPSBjKDAsIHptYXgpLCBsb29wID0gbG9vcHMpCiAgcDIgPC0gcGxvdE1hdHJpeChoaWMyLCBkcGkgPSAxMDAwLCBsaW1pdHMgPSBjKDAsIHptYXgpLCBsb29wID0gbG9vcHMpCiAgCiAgZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgidmlzdXpsaWF0aW9uX3JlZ0xvb3BfZFRBR18iLCBpLCAiXzI1a2IiKSkKICBwbmcocGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCiAgZGV2Lm9mZigpCiAgIyBzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkKICAjIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKICAjIGRldi5vZmYoKQojIH0KCiMjIyMjIyMjIyMjIyMjIFN0cgojIyBGaWx0ZXJpbmcgbG9vcHMgdG8gcGxvdApkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfc2NvcmUudHN2IikpCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIHN0cklELCBkVEFHID4gMC41KSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhkVEFHKSkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6c2VsZWN0KHNlcSgxLCA2KSkKY29sbmFtZXModGVtcCkgPC0gYygiVjEiLCAiVjIiLCAiVjMiLCAiVjQiLCAiVjUiLCAiVjYiKQpsb29wcyA8LSBpbXBvcnRCZWRwZSh0ZW1wKQoKIyBWaXN1YWxpemF0aW9uCmhpY0RpciA8LSAiL1ZvbHVtZXMvVUtKSU5fU1NEL0dlbm9taWNzXzAzX0FuYWx5c2lzX1dvcmtpbmcvZGF0YV92YXVsdF8yMDI0c3VtbWVyX21pY3JvQy9oaWMiCndpbmRvd1NpemUgPC0gMioxZTYKCmZvcihpIGluIHNlcSgxLCAyNSkpewogICMjIExvYWRpbmcgaGljIGFuZCBwbG90dGluZwogIGNociA8LSBhc190aWJibGUobG9vcHNbaV0pJHNlcW5hbWVzMQogIGNlbnRlciA8LSAoYXNfdGliYmxlKGxvb3BzW2ldKSRzdGFydDEgKyBhc190aWJibGUobG9vcHNbaV0pJGVuZDIpLzIKICBzdGFydCA8LSBmbG9vcihjZW50ZXIgLSAwLjUqd2luZG93U2l6ZSkKICBlbmQgPC0gZmxvb3IoY2VudGVyICsgMC41KndpbmRvd1NpemUpCiAgCiAgY2YuRzFETVNPIDwtIEhpY0ZpbGUocGF0aCA9IGhlcmUoaGljRGlyLCAiRzEuRE1TTy5NZXJnZWQuaGljIikpCiAgY2YuRzFkVEFHIDwtIEhpY0ZpbGUocGF0aCA9IGhlcmUoaGljRGlyLCAiRzEuZFRBRy5NZXJnZWQuaGljIikpCgogIHJlcyA8LSAxMCoxMDAwCiAgem1heCA8LSAyLjUKICBoaWMxIDwtIGltcG9ydChjZi5HMURNU08sIGZvY3VzID0gcGFzdGUwKGNociwgIjoiLCBzdGFydCwgIi0iLCBlbmQpLCByZXNvbHV0aW9uID0gcmVzKQogIGhpYzIgPC0gaW1wb3J0KGNmLkcxZFRBRywgZm9jdXMgPSBwYXN0ZTAoY2hyLCAiOiIsIHN0YXJ0LCAiLSIsIGVuZCksIHJlc29sdXRpb24gPSByZXMpCiAgcDEgPC0gcGxvdE1hdHJpeChoaWMxLCBkcGkgPSAxMDAwLCBsaW1pdHMgPSBjKDAsIHptYXgpLCBsb29wID0gbG9vcHMpCiAgcDIgPC0gcGxvdE1hdHJpeChoaWMyLCBkcGkgPSAxMDAwLCBsaW1pdHMgPSBjKDAsIHptYXgpLCBsb29wID0gbG9vcHMpCiAgCiAgZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgidmlzdXpsaWF0aW9uX3N0ckxvb3BfZFRBR18iLCBpLCAiXzEwa2IiKSkKICBwbmcocGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBhbGlnbiA9ICJoIikpCiAgZGV2Lm9mZigpCiAgCiAgCiAgcmVzIDwtIDI1KjEwMDAKICB6bWF4IDwtIDMKICBzdGFydCA8LSBmbG9vcihjZW50ZXIgLSB3aW5kb3dTaXplKQogIGVuZCA8LSBmbG9vcihjZW50ZXIgKyB3aW5kb3dTaXplKQogIGhpYzEgPC0gaW1wb3J0KGNmLkcxRE1TTywgZm9jdXMgPSBwYXN0ZTAoY2hyLCAiOiIsIHN0YXJ0LCAiLSIsIGVuZCksIHJlc29sdXRpb24gPSByZXMpCiAgaGljMiA8LSBpbXBvcnQoY2YuRzFkVEFHLCBmb2N1cyA9IHBhc3RlMChjaHIsICI6Iiwgc3RhcnQsICItIiwgZW5kKSwgcmVzb2x1dGlvbiA9IHJlcykKICBwMSA8LSBwbG90TWF0cml4KGhpYzEsIGRwaSA9IDEwMDAsIGxpbWl0cyA9IGMoMCwgem1heCksIGxvb3AgPSBsb29wcykKICBwMiA8LSBwbG90TWF0cml4KGhpYzIsIGRwaSA9IDEwMDAsIGxpbWl0cyA9IGMoMCwgem1heCksIGxvb3AgPSBsb29wcykKICAKICBmaWxlTmFtZSA8LSBoZXJlKGZpZ0RpciwgcGFzdGUwKCJ2aXN1emxpYXRpb25fc3RyTG9vcF9kVEFHXyIsIGksICJfMjVrYiIpKQogIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKICBkZXYub2ZmKCkKfQoKIyMjIyMjIyMjIyMjIyMgZFRBRyBjYWxsZWQgbG9vcHMKIyMgRmlsdGVyaW5nIGxvb3BzIHRvIHBsb3QKZGF0YTEgPC0gZnJlYWQoaGVyZShsb29wRGlyLCAiRzEuZFRBRy5NZXJnZWRfY2hyb21vc2lnaHRfMjVrYi50c3YiKSkKZGF0YTIgPC0gZnJlYWQoaGVyZShsb29wRGlyLCAiRzEuZFRBRy5NZXJnZWRfY2hyb21vc2lnaHRfMTBrYi50c3YiKSkKZGF0YTMgPC0gZnJlYWQoaGVyZShsb29wRGlyLCAiRzEuZFRBRy5NZXJnZWRfY2hyb21vc2lnaHRfNWtiLnRzdiIpKQpkYXRhIDwtIGJpbmRfcm93cyhkYXRhMSwgZGF0YTIsIGRhdGEzKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKHNjb3JlKSkKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OnNlbGVjdChzZXEoMSwgNikpCmNvbG5hbWVzKHRlbXApIDwtIGMoIlYxIiwgIlYyIiwgIlYzIiwgIlY0IiwgIlY1IiwgIlY2IikKbG9vcHMgPC0gaW1wb3J0QmVkcGUodGVtcCkKCiMgVmlzdWFsaXphdGlvbgpoaWNEaXIgPC0gIi9Wb2x1bWVzL1VLSklOX1NTRC9HZW5vbWljc18wM19BbmFseXNpc19Xb3JraW5nL2RhdGFfdmF1bHRfMjAyNHN1bW1lcl9taWNyb0MvaGljIgp3aW5kb3dTaXplIDwtIDIqMWU2Cgpmb3IoaSBpbiBzZXEoMSwgMjUpKXsKICAjIyBMb2FkaW5nIGhpYyBhbmQgcGxvdHRpbmcKICBjaHIgPC0gYXNfdGliYmxlKGxvb3BzW2ldKSRzZXFuYW1lczEKICBjZW50ZXIgPC0gKGFzX3RpYmJsZShsb29wc1tpXSkkc3RhcnQxICsgYXNfdGliYmxlKGxvb3BzW2ldKSRlbmQyKS8yCiAgc3RhcnQgPC0gZmxvb3IoY2VudGVyIC0gMC41KndpbmRvd1NpemUpCiAgZW5kIDwtIGZsb29yKGNlbnRlciArIDAuNSp3aW5kb3dTaXplKQogIAogIGNmLkcxRE1TTyA8LSBIaWNGaWxlKHBhdGggPSBoZXJlKGhpY0RpciwgIkcxLkRNU08uTWVyZ2VkLmhpYyIpKQogIGNmLkcxZFRBRyA8LSBIaWNGaWxlKHBhdGggPSBoZXJlKGhpY0RpciwgIkcxLmRUQUcuTWVyZ2VkLmhpYyIpKQoKICByZXMgPC0gMTAqMTAwMAogIHptYXggPC0gMi41CiAgaGljMSA8LSBpbXBvcnQoY2YuRzFETVNPLCBmb2N1cyA9IHBhc3RlMChjaHIsICI6Iiwgc3RhcnQsICItIiwgZW5kKSwgcmVzb2x1dGlvbiA9IHJlcykKICBoaWMyIDwtIGltcG9ydChjZi5HMWRUQUcsIGZvY3VzID0gcGFzdGUwKGNociwgIjoiLCBzdGFydCwgIi0iLCBlbmQpLCByZXNvbHV0aW9uID0gcmVzKQogIHAxIDwtIHBsb3RNYXRyaXgoaGljMSwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIHAyIDwtIHBsb3RNYXRyaXgoaGljMiwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIAogIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCBwYXN0ZTAoInZpc3V6bGlhdGlvbl9kVEFHY2FsbGVkTG9vcF9kVEFHXyIsIGksICJfMTBrYiIpKQogIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKICBkZXYub2ZmKCkKICAKICAKICByZXMgPC0gMjUqMTAwMAogIHptYXggPC0gMwogIHN0YXJ0IDwtIGZsb29yKGNlbnRlciAtIHdpbmRvd1NpemUpCiAgZW5kIDwtIGZsb29yKGNlbnRlciArIHdpbmRvd1NpemUpCiAgaGljMSA8LSBpbXBvcnQoY2YuRzFETVNPLCBmb2N1cyA9IHBhc3RlMChjaHIsICI6Iiwgc3RhcnQsICItIiwgZW5kKSwgcmVzb2x1dGlvbiA9IHJlcykKICBoaWMyIDwtIGltcG9ydChjZi5HMWRUQUcsIGZvY3VzID0gcGFzdGUwKGNociwgIjoiLCBzdGFydCwgIi0iLCBlbmQpLCByZXNvbHV0aW9uID0gcmVzKQogIHAxIDwtIHBsb3RNYXRyaXgoaGljMSwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIHAyIDwtIHBsb3RNYXRyaXgoaGljMiwgZHBpID0gMTAwMCwgbGltaXRzID0gYygwLCB6bWF4KSwgbG9vcCA9IGxvb3BzKQogIAogIGZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCBwYXN0ZTAoInZpc3V6bGlhdGlvbl9kVEFHY2FsbGVkTG9vcF9kVEFHXyIsIGksICJfMjVrYiIpKQogIHBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKICBkZXYub2ZmKCkKfQoKY2hyID0gImNocjEzIgpzdGFydCA9IDk2OTAwMDAwCmVuZCA9IDk4MTAwMDAwCiAgcmVzIDwtIDEwKjEwMDAKICB6bWF4IDwtIDIuNQogIGhpYzEgPC0gaW1wb3J0KGNmLkcxRE1TTywgZm9jdXMgPSBwYXN0ZTAoY2hyLCAiOiIsIHN0YXJ0LCAiLSIsIGVuZCksIHJlc29sdXRpb24gPSByZXMpCiAgaGljMiA8LSBpbXBvcnQoY2YuRzFkVEFHLCBmb2N1cyA9IHBhc3RlMChjaHIsICI6Iiwgc3RhcnQsICItIiwgZW5kKSwgcmVzb2x1dGlvbiA9IHJlcykKICBwMSA8LSBwbG90TWF0cml4KGhpYzEsIGRwaSA9IDEwMDAsIGxpbWl0cyA9IGMoMCwgem1heCkpCiAgcDIgPC0gcGxvdE1hdHJpeChoaWMyLCBkcGkgPSAxMDAwLCBsaW1pdHMgPSBjKDAsIHptYXgpKQogICAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgYWxpZ24gPSAiaCIpKQoKYGBgCgojIyBbMi4zMl0gSGVhdG1hcCBvZiBsb29wcwpTdHJhdGVneTogY2hlY2sgb3ZlcmxhcCBvZiB0aGUgdW5pb24gbG9vcHMgdG8gdGhlIGxvb3BzIGNhbGxlZCBhdCBlYWNoIGNvbmRpdGlvbgojIyMjIENoZWNrIHNhbXBsZSBzcGVjaWZpYyBjYWxsZWQgbG9vcHMKYGBge3J9CmxpYnJhcnkoY2lyY2xpemUpCgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChzZXEoMSwgNikpCmNvbG5hbWVzKHRlbXApIDwtIGMoIlYxIiwgIlYyIiwgIlYzIiwgIlY0IiwgIlY1IiwgIlY2IikKY29ucy5sb29wIDwtIGltcG9ydEJlZHBlKHRlbXApCgojIENoZWNraW5nIERNU08KbG9vcC4yNWtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5ETVNPLk1lcmdlZF9jaHJvbW9zaWdodF8iLCAyNSwgImtiLmJlZHBlIikpKSkKbG9vcC4xMGtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5ETVNPLk1lcmdlZF9jaHJvbW9zaWdodF8iLCAxMCwgImtiLmJlZHBlIikpKSkKbG9vcC41a2IgPC0gaW1wb3J0QmVkcGUoZnJlYWQoaGVyZShsb29wRGlyLCBwYXN0ZTAoIkcxLkRNU08uTWVyZ2VkX2Nocm9tb3NpZ2h0XyIsIDUsICJrYi5iZWRwZSIpKSkpCgoKb3ZlcmxhcC4yNWtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMjVrYikKb3ZlcmxhcC4xMGtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMTBrYikKb3ZlcmxhcC41a2IgPC0gZmluZE92ZXJsYXBzKGNvbnMubG9vcCwgbG9vcC41a2IpCgppbmRleCA8LSBzb3J0KHVuaXF1ZShjKHF1ZXJ5SGl0cyhvdmVybGFwLjI1a2IpLAogICAgICAgICBxdWVyeUhpdHMob3ZlcmxhcC4xMGtiKSwKICAgICAgICAgcXVlcnlIaXRzKG92ZXJsYXAuNWtiKSkpKQpkYXRhJGNhbGxlZEJ5RE1TTyA8LSAwCmRhdGEkY2FsbGVkQnlETVNPW2luZGV4XSA8LSAxCgojIENoZWNraW5nIGRUQUcKbG9vcC4yNWtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5kVEFHLk1lcmdlZF9jaHJvbW9zaWdodF8iLCAyNSwgImtiLmJlZHBlIikpKSkKbG9vcC4xMGtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5kVEFHLk1lcmdlZF9jaHJvbW9zaWdodF8iLCAxMCwgImtiLmJlZHBlIikpKSkKbG9vcC41a2IgPC0gaW1wb3J0QmVkcGUoZnJlYWQoaGVyZShsb29wRGlyLCBwYXN0ZTAoIkcxLmRUQUcuTWVyZ2VkX2Nocm9tb3NpZ2h0XyIsIDUsICJrYi5iZWRwZSIpKSkpCgoKb3ZlcmxhcC4yNWtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMjVrYikKb3ZlcmxhcC4xMGtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMTBrYikKb3ZlcmxhcC41a2IgPC0gZmluZE92ZXJsYXBzKGNvbnMubG9vcCwgbG9vcC41a2IpCgppbmRleCA8LSBzb3J0KHVuaXF1ZShjKHF1ZXJ5SGl0cyhvdmVybGFwLjI1a2IpLAogICAgICAgICBxdWVyeUhpdHMob3ZlcmxhcC4xMGtiKSwKICAgICAgICAgcXVlcnlIaXRzKG92ZXJsYXAuNWtiKSkpKQpkYXRhJGNhbGxlZEJ5ZFRBRyA8LSAwCmRhdGEkY2FsbGVkQnlkVEFHW2luZGV4XSA8LSAxCgojIENoZWNraW5nIEE0ODUKbG9vcC4yNWtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5BNDg1Lk1lcmdlZF9jaHJvbW9zaWdodF8iLCAyNSwgImtiLmJlZHBlIikpKSkKbG9vcC4xMGtiIDwtIGltcG9ydEJlZHBlKGZyZWFkKGhlcmUobG9vcERpciwgcGFzdGUwKCJHMS5BNDg1Lk1lcmdlZF9jaHJvbW9zaWdodF8iLCAxMCwgImtiLmJlZHBlIikpKSkKbG9vcC41a2IgPC0gaW1wb3J0QmVkcGUoZnJlYWQoaGVyZShsb29wRGlyLCBwYXN0ZTAoIkcxLkE0ODUuTWVyZ2VkX2Nocm9tb3NpZ2h0XyIsIDUsICJrYi5iZWRwZSIpKSkpCgoKb3ZlcmxhcC4yNWtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMjVrYikKb3ZlcmxhcC4xMGtiIDwtIGZpbmRPdmVybGFwcyhjb25zLmxvb3AsIGxvb3AuMTBrYikKb3ZlcmxhcC41a2IgPC0gZmluZE92ZXJsYXBzKGNvbnMubG9vcCwgbG9vcC41a2IpCgppbmRleCA8LSBzb3J0KHVuaXF1ZShjKHF1ZXJ5SGl0cyhvdmVybGFwLjI1a2IpLAogICAgICAgICBxdWVyeUhpdHMob3ZlcmxhcC4xMGtiKSwKICAgICAgICAgcXVlcnlIaXRzKG92ZXJsYXAuNWtiKSkpKQpkYXRhJGNhbGxlZEJ5QTQ4NSA8LSAwCmRhdGEkY2FsbGVkQnlBNDg1W2luZGV4XSA8LSAxCgoKIyBIZWF0bWFwIChjaGVja2luZyB3aGV0aGVyIGNlcnRhaW4gcGVhayBpcyBjYWxsZWQgYnkgc3BlY2lmaWMgc2FtcGxlKQpkYXRhVG9QbG90IDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoaWQsIGNhbGxlZEJ5RE1TTywgY2FsbGVkQnlkVEFHLCBjYWxsZWRCeUE0ODUpCmRhdGFUb1Bsb3QgPC0gZGF0YVRvUGxvdCAlPiUgZHBseXI6Om11dGF0ZShmbGFnID0gNCpjYWxsZWRCeURNU08gKyAyKmNhbGxlZEJ5ZFRBRyArIGNhbGxlZEJ5QTQ4NSkgJT4lCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhmbGFnKSkKCnJvd19ncm91cHMgPC0gZGF0YVRvUGxvdCRmbGFnCmRhdGFfbWF0cml4IDwtIGRhdGFUb1Bsb3QgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiaWQiKSAlPiUgZHBseXI6OnNlbGVjdCgtZmxhZykgJT4lIGFzLm1hdHJpeCgpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgIGMoIndoaXRlIiwgImdyZWVuIikpCmgxIDwtIEhlYXRtYXAoZGF0YV9tYXRyaXgsIG5hbWUgPSAiY2FsbGVkQnkiLAogICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBib3JkZXIgPSBUUlVFLAogICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgY29sID0gY29sX2Z1biwKICAgICAgICByb3dfc3BsaXQgPSByb3dfZ3JvdXBzKQoKCiMgUHJlcGFyZSBkYXRhIGZvciB0aGUgc2Vjb25kIGhlYXRtYXAKZGF0YVRvUGxvdDIgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChpZCwgRE1TTywgZFRBRywgQTQ4NSkgJT4lCiAgYXJyYW5nZShtYXRjaChpZCwgZGF0YVRvUGxvdCRpZCkpCgpkYXRhX21hdHJpeDIgPC0gZGF0YVRvUGxvdDIgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiaWQiKSAlPiUgYXMubWF0cml4KCkKCgpjb2xfZnVuMiA8LSBjb2xvclJhbXAyKGMoLTAuNSwgMCwgMSksIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCgpoMiA8LSBIZWF0bWFwKGRhdGFfbWF0cml4MiwgbmFtZSA9ICJzY29yZSIsCiAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgYm9yZGVyID0gVFJVRSwKICAgICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgIGNvbCA9IGNvbF9mdW4yLAogICAgICAgICAgICAgIHJvd19zcGxpdCA9IHJvd19ncm91cHMpCgoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgiaGVhdG1hcF9jaGVja2luZ1NhbXBsZUNhbGxlZExvb3BzIikpCnBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDMsIGhlaWdodCA9IDEwKQpwcmludChoMSArIGgyKQpkZXYub2ZmKCkKCmBgYAojIyMjIENoZWNraW5nIHVwZG93bgojIyMjIyBBbGwgbG9vcHMKYGBge3J9CiMgSGVhdG1hcApsaWJyYXJ5KGNpcmNsaXplKQoKIyBIZWF0bWFwIDIKc2V0LnNlZWQoMTIzKQoKZGlmZkN1dG9mZiA8LSAwLjIKZGF0YVRvUGxvdCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGlzZGlmZl9kVEFHX0RNU08gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZV93aGVuKGRpZmZfZFRBR19ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJzKGRpZmZfZFRBR19ETVNPKSA8IGRpZmZDdXRvZmYgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZl9kVEFHX0RNU08gPD0gLWRpZmZDdXRvZmYgfiAtMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc2RpZmZfQTQ4NV9ETVNPID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2Vfd2hlbihkaWZmX0E0ODVfRE1TTyA+PSBkaWZmQ3V0b2ZmIH4gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFicyhkaWZmX0E0ODVfRE1TTykgPCBkaWZmQ3V0b2ZmIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZfQTQ4NV9ETVNPIDw9IC1kaWZmQ3V0b2ZmIH4gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkEpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGlkLCBpc2RpZmZfZFRBR19ETVNPLCBpc2RpZmZfQTQ4NV9ETVNPKQpkYXRhX21hdHJpeCA8LSBkYXRhVG9QbG90ICU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gImlkIiklPiUgYXMubWF0cml4KCkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTEsIDAsIDEpLCBjKCJibHVlIiwgImdyZXkiLCAicmVkIikpCmgxIDwtIEhlYXRtYXAoZGF0YV9tYXRyaXgsIG5hbWUgPSAibG9vcCBzY29yZSIsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgcm93X2ttID0gOSwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgYm9yZGVyID0gRkFMU0UsCiAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBGQUxTRSwKICAgICAgICBjb2wgPSBjb2xfZnVuKQoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgiaGVhdG1hcF9jaGVja2luZ0RlbHRhQWNyb3NzQ29uZGl0aW9uIikpCnBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDIsIGhlaWdodCA9IDEwKQpwcmludChoMSkKZGV2Lm9mZigpCgpzZXQuc2VlZCgxMjMpCgpobV9kcmF3biA8LSBkcmF3KGgxKQpyb3dfY2x1c3RlcnMgPC0gcm93X29yZGVyKGhtX2RyYXduKQoKbG9vcC5jbHVzdGVyMSA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbMV1dXQpsb29wLmNsdXN0ZXIyIDwtIHRlbXBbcm93X2NsdXN0ZXJzW1syXV1dCmxvb3AuY2x1c3RlcjMgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzNdXV0KbG9vcC5jbHVzdGVyNCA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbNF1dXQpsb29wLmNsdXN0ZXI1IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s1XV1dCmxvb3AuY2x1c3RlcjYgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzZdXV0KbG9vcC5jbHVzdGVyNyA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbN11dXQpsb29wLmNsdXN0ZXI4IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s4XV1dCmxvb3AuY2x1c3RlcjkgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzldXV0KCmBgYAoKIyMjIyMgUmVnIGxvb3BzCmBgYHtyfQojIEhlYXRtYXAKbGlicmFyeShjaXJjbGl6ZSkKCiMgSGVhdG1hcCAyCnNldC5zZWVkKDEyMykKCmRpZmZDdXRvZmYgPC0gMC4yCmRhdGFUb1Bsb3QgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlAtUCIsICJQLUUiLCAiRS1FIikpICU+JQogIGRwbHlyOjptdXRhdGUoaXNkaWZmX2RUQUdfRE1TTyA9IAogICAgICAgICAgICAgICAgICBjYXNlX3doZW4oZGlmZl9kVEFHX0RNU08gPj0gZGlmZkN1dG9mZiB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMoZGlmZl9kVEFHX0RNU08pIDwgZGlmZkN1dG9mZiB+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmX2RUQUdfRE1TTyA8PSAtZGlmZkN1dG9mZiB+IC0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BKSwKICAgICAgICAgICAgICAgIGlzZGlmZl9BNDg1X0RNU08gPSAKICAgICAgICAgICAgICAgICAgY2FzZV93aGVuKGRpZmZfQTQ4NV9ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJzKGRpZmZfQTQ4NV9ETVNPKSA8IGRpZmZDdXRvZmYgfiAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZl9BNDg1X0RNU08gPD0gLWRpZmZDdXRvZmYgfiAtMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpICU+JQogIGRwbHlyOjpzZWxlY3QoaWQsIGlzZGlmZl9kVEFHX0RNU08sIGlzZGlmZl9BNDg1X0RNU08pCmRhdGFfbWF0cml4IDwtIGRhdGFUb1Bsb3QgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiaWQiKSU+JSBhcy5tYXRyaXgoKQpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYygtMSwgMCwgMSksIGMoImJsdWUiLCAiZ3JleSIsICJyZWQiKSkKaDEgPC0gSGVhdG1hcChkYXRhX21hdHJpeCwgbmFtZSA9ICJsb29wIHNjb3JlIiwKICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICByb3dfa20gPSA4LAogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICAgICAgICBib3JkZXIgPSBGQUxTRSwKICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLAogICAgICAgIGNvbCA9IGNvbF9mdW4pCgpmaWxlTmFtZSA8LSBoZXJlKGZpZ0RpciwgcGFzdGUwKCJoZWF0bWFwX2NoZWNraW5nRGVsdGFBY3Jvc3NDb25kaXRpb25fcmVnIikpCnBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDIsIGhlaWdodCA9IDEwKQpwcmludChoMSkKZGV2Lm9mZigpCgpzZXQuc2VlZCgxMjMpCgpobV9kcmF3biA8LSBkcmF3KGgxKQpyb3dfY2x1c3RlcnMgPC0gcm93X29yZGVyKGhtX2RyYXduKQoKbG9vcC5jbHVzdGVyMSA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbMV1dXQpsb29wLmNsdXN0ZXIyIDwtIHRlbXBbcm93X2NsdXN0ZXJzW1syXV1dCmxvb3AuY2x1c3RlcjMgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzNdXV0KbG9vcC5jbHVzdGVyNCA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbNF1dXQpsb29wLmNsdXN0ZXI1IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s1XV1dCmxvb3AuY2x1c3RlcjYgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzZdXV0KbG9vcC5jbHVzdGVyNyA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbN11dXQpsb29wLmNsdXN0ZXI4IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s4XV1dCgpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNpcmNsaXplKQoKc2V0LnNlZWQoMTIzKQpkYXRhVG9QbG90IDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGlkLCBkaWZmX2RUQUdfRE1TTywgZGlmZl9BNDg1X0RNU08pCmRhdGFfbWF0cml4IDwtIGRhdGFUb1Bsb3QgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiaWQiKSU+JSBhcy5tYXRyaXgoKQpjb2xfZnVuIDwtIGNvbG9yUmFtcDIoYygtMSwgMCwgMSksIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCmgxIDwtIEhlYXRtYXAoZGF0YV9tYXRyaXgsIG5hbWUgPSAibG9vcCBzY29yZSIsCiAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgcm93X2ttID0gNCwKICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgYm9yZGVyID0gVFJVRSwKICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLAogICAgICAgIGNvbCA9IGNvbF9mdW4pCgoKZmlsZU5hbWUgPC0gaGVyZShmaWdEaXIsIHBhc3RlMCgiaGVhdG1hcF9kaWZmU2NvcmVfcmVnX2s0IikpCnBuZyhwYXN0ZTAoZmlsZU5hbWUsICIucG5nIiksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDIsIGhlaWdodCA9IDYpCnByaW50KGgxKQpkZXYub2ZmKCkKCmhtX2RyYXduIDwtIGRyYXcoaDEpCnJvd19jbHVzdGVycyA8LSByb3dfb3JkZXIoaG1fZHJhd24pCgpsb29wLmNsdXN0ZXIxIDwtIHRlbXBbcm93X2NsdXN0ZXJzW1sxXV1dCmxvb3AuY2x1c3RlcjIgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzJdXV0KbG9vcC5jbHVzdGVyMyA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbM11dXQpsb29wLmNsdXN0ZXI0IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s0XV1dCmBgYAojIyMjIyBBbGwgbG9vcHMgX09FCmBgYHtyfQojIEhlYXRtYXAKbGlicmFyeShjaXJjbGl6ZSkKCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKIyBIZWF0bWFwIDIKc2V0LnNlZWQoMTIzKQoKIyBJbXBvcnQgb2JzL2V4cCBzY29yZXMgYW5kIG1lcmdlIHRvIHRoZSBkYXRhc2V0Cm1pblZhbHVlIDwtIC00CmRpZmZDdXRvZmYgPC0gMC41Cm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCgojIE1lcmdlIGRhdGFzZXQKZGF0YVRvUGxvdCA8LSBkYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKG9ic2V4cCwgYnkgPSBjKCJpZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPSBsb2dfb2JzZXhwX2RUQUcgLSBsb2dfb2JzZXhwX0RNU08sCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID0gbG9nX29ic2V4cF9BNDg1IC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgaXNkaWZmX2RUQUdfRE1TTyA9IGNhc2Vfd2hlbihsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTykgPCBkaWZmQ3V0b2ZmIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA8PSBkaWZmQ3V0b2ZmIH4gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSApLAogICAgICAgICAgICAgICAgaXNkaWZmX0E0ODVfRE1TTyA9IGNhc2Vfd2hlbihsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMobG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTykgPCBkaWZmQ3V0b2ZmIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA8PSBkaWZmQ3V0b2ZmIH4gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpJT4lCiAgZHBseXI6OnNlbGVjdChpZCwgaXNkaWZmX2RUQUdfRE1TTywgaXNkaWZmX0E0ODVfRE1TTykKCgoKZGF0YV9tYXRyaXggPC0gZGF0YVRvUGxvdCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJpZCIpJT4lIGFzLm1hdHJpeCgpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKC0xLCAwLCAxKSwgYygiYmx1ZSIsICJncmV5IiwgInJlZCIpKQpoMSA8LSBIZWF0bWFwKGRhdGFfbWF0cml4LCBuYW1lID0gImxvb3Agc2NvcmUiLAogICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHJvd19rbSA9IDksCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogICAgICAgIGJvcmRlciA9IEZBTFNFLAogICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgY29sID0gY29sX2Z1bikKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCBwYXN0ZTAoImhlYXRtYXBfY2hlY2tpbmdEZWx0YUFjcm9zc0NvbmRpdGlvbl9PRSIpKQpwbmcocGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpLCByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSAyLCBoZWlnaHQgPSAxMCkKcHJpbnQoaDEpCmRldi5vZmYoKQojIAojIHNldC5zZWVkKDEyMykKIyAKIyBobV9kcmF3biA8LSBkcmF3KGgxKQojIHJvd19jbHVzdGVycyA8LSByb3dfb3JkZXIoaG1fZHJhd24pCiMgCiMgbG9vcC5jbHVzdGVyMSA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbMV1dXQojIGxvb3AuY2x1c3RlcjIgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzJdXV0KIyBsb29wLmNsdXN0ZXIzIDwtIHRlbXBbcm93X2NsdXN0ZXJzW1szXV1dCiMgbG9vcC5jbHVzdGVyNCA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbNF1dXQojIGxvb3AuY2x1c3RlcjUgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzVdXV0KIyBsb29wLmNsdXN0ZXI2IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s2XV1dCiMgbG9vcC5jbHVzdGVyNyA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbN11dXQojIGxvb3AuY2x1c3RlcjggPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzhdXV0KIyBsb29wLmNsdXN0ZXI5IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s5XV1dCgpgYGAKIyMjIyMgUmVnIGxvb3BzIF9PRQpgYGB7cn0KIyBIZWF0bWFwCmxpYnJhcnkoY2lyY2xpemUpCgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCiMgSGVhdG1hcCAyCnNldC5zZWVkKDEyMykKCiMgSW1wb3J0IG9icy9leHAgc2NvcmVzIGFuZCBtZXJnZSB0byB0aGUgZGF0YXNldAptaW5WYWx1ZSA8LSAtNApkaWZmQ3V0b2ZmIDwtIDAuNQpvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSkpCgoKIyBNZXJnZSBkYXRhc2V0CmRhdGFUb1Bsb3QgPC0gZGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPSBsb2dfb2JzZXhwX2RUQUcgLSBsb2dfb2JzZXhwX0RNU08sCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID0gbG9nX29ic2V4cF9BNDg1IC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgaXNkaWZmX2RUQUdfRE1TTyA9IGNhc2Vfd2hlbihsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTykgPCBkaWZmQ3V0b2ZmIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA8PSBkaWZmQ3V0b2ZmIH4gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSApLAogICAgICAgICAgICAgICAgaXNkaWZmX0E0ODVfRE1TTyA9IGNhc2Vfd2hlbihsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID49IGRpZmZDdXRvZmYgfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMobG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTykgPCBkaWZmQ3V0b2ZmIH4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA8PSBkaWZmQ3V0b2ZmIH4gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpJT4lCiAgZHBseXI6OnNlbGVjdChpZCwgaXNkaWZmX2RUQUdfRE1TTywgaXNkaWZmX0E0ODVfRE1TTykKCgoKZGF0YV9tYXRyaXggPC0gZGF0YVRvUGxvdCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJpZCIpJT4lIGFzLm1hdHJpeCgpCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKC0xLCAwLCAxKSwgYygiYmx1ZSIsICJncmV5IiwgInJlZCIpKQpoMSA8LSBIZWF0bWFwKGRhdGFfbWF0cml4LCBuYW1lID0gImxvb3Agc2NvcmUiLAogICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHJvd19rbSA9IDksCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogICAgICAgIGJvcmRlciA9IEZBTFNFLAogICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgY29sID0gY29sX2Z1bikKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCBwYXN0ZTAoImhlYXRtYXBfY2hlY2tpbmdEZWx0YUFjcm9zc0NvbmRpdGlvbl9yZWdfT0UiKSkKcG5nKHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSwgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gMiwgaGVpZ2h0ID0gMTApCnByaW50KGgxKQpkZXYub2ZmKCkKIyAKIyBzZXQuc2VlZCgxMjMpCiMgCiMgaG1fZHJhd24gPC0gZHJhdyhoMSkKIyByb3dfY2x1c3RlcnMgPC0gcm93X29yZGVyKGhtX2RyYXduKQojIAojIGxvb3AuY2x1c3RlcjEgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzFdXV0KIyBsb29wLmNsdXN0ZXIyIDwtIHRlbXBbcm93X2NsdXN0ZXJzW1syXV1dCiMgbG9vcC5jbHVzdGVyMyA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbM11dXQojIGxvb3AuY2x1c3RlcjQgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzRdXV0KIyBsb29wLmNsdXN0ZXI1IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s1XV1dCiMgbG9vcC5jbHVzdGVyNiA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbNl1dXQojIGxvb3AuY2x1c3RlcjcgPC0gdGVtcFtyb3dfY2x1c3RlcnNbWzddXV0KIyBsb29wLmNsdXN0ZXI4IDwtIHRlbXBbcm93X2NsdXN0ZXJzW1s4XV1dCiMgbG9vcC5jbHVzdGVyOSA8LSB0ZW1wW3Jvd19jbHVzdGVyc1tbOV1dXQoKYGBgCiMjIyBbMi4zMl0gQ29tcGFyaW5nIHdpdGggQm9iYmllJ3MgZGF0YQpXaGVyZSBkb2VzIGRpZmZlcmVudGlhdGVkIHJlbGF0ZWQgZ2VuZXMgZmFsbCBpbnRvPwpgYGB7cn0KbWFyZ2luRXJyb3IgPC0gZnVuY3Rpb24obXlMaXN0KSB7CiAgc2FtcGxlLm4gPSBsZW5ndGgobXlMaXN0KQogIHNhbXBsZS5zZCA9IHNkKG15TGlzdCkKICBzYW1wbGUuc2UgPSBzYW1wbGUuc2Qvc3FydChzYW1wbGUubikKICBhbHBoYSA9IDAuMDUKICBkZWdyZWVzLmZyZWVkb20gPSBzYW1wbGUubiAtIDEKICB0LnNjb3JlID0gcXQocCA9IGFscGhhLzIsIGRmID0gZGVncmVlcy5mcmVlZG9tLCBsb3dlci50YWlsID0gRikKICBtYXJnaW4uZXJyb3IgPSB0LnNjb3JlKnNhbXBsZS5zZQogIHJldHVybihtYXJnaW4uZXJyb3IpCn0KClBST3NlcS5ib2JiaWUgPC0gYXNfdGliYmxlKGZyZWFkKGhlcmUocmVmRGlyLCAiYm9iYmllX2dlbmVfY2xhc3NpZmljYXRpb24uY3N2IikpKQoKZ2VuZUxpc3QuRXBpLmRUQUcudXAgPC0gKGZyZWFkKGhlcmUocmVmRGlyLCAiZGlmZl9HMS5kVEFHX0cxLkVwaS5kVEFHX3ZzX0cxLkVwaS5ETVNPLnRzdiIpKSAlPiUgZHBseXI6OmZpbHRlcihwYWRqIDwgMC4wNSwgbG9nMkZvbGRDaGFuZ2UgPiAwKSkkZW5zZW1ibF9nZW5lX2lkCgpnZW5lTGlzdC5FcGkuZFRBRy5kb3duIDwtIChmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS5FcGkuZFRBR192c19HMS5FcGkuRE1TTy50c3YiKSkgJT4lIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUsIGxvZzJGb2xkQ2hhbmdlIDwgMCkpJGVuc2VtYmxfZ2VuZV9pZAoKIyMgQ29udmVydGluZyB0cmFuc2NyaXB0IElEIHRvIGdlbmUgSUQKaWRQYWlyX3RnIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLCAiZW5zZW1ibF9nZW5lX2lkIiksCiAgICAgICAgICAgICAgICAgZmlsdGVycyA9ICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLAogICAgICAgICAgICAgICAgIHZhbHVlcyA9IFBST3NlcS5ib2JiaWUkZW5zdCwKICAgICAgICAgICAgICAgICBtYXJ0ID0gZW5zZW1ibC52MTAyKQpQUk9zZXEuYm9iYmllIDwtIFBST3NlcS5ib2JiaWUgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oaWRQYWlyX3RnLCBieSA9IGMoImVuc3QiID0gImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIpKQoKIyMgQmFyIFBsb3QKdGVtcCA8LSBQUk9zZXEuYm9iYmllICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGdlbmVMaXN0LkVwaS5kVEFHLmRvd24pCgpncm91cCA8LSBjKHJlcCgiRXBpTENfZFRBR3ZzRE1TT19ET1dOIiwgNCkpCmNsdXN0ZXIgPC0gcmVwKGMoIkVhcmx5IiwgIk1pZGRsZSIsICJMYXRlIiwgIlRyYW5zaWVudCIpLCAxKQpjbHVzdGVyIDwtIGZhY3RvcihjbHVzdGVyLCBsZXZlbHMgPSBjKCJFYXJseSIsICJNaWRkbGUiLCAiTGF0ZSIsICJUcmFuc2llbnQiKSkKdmFsdWUgPC0gYyhzdW0odGVtcCRDbHVzdGVyID09ICJFYXJseSIpLAogICAgICAgICAgIHN1bSh0ZW1wJENsdXN0ZXIgPT0gIk1pZGRsZSIpLAogICAgICAgICAgIHN1bSh0ZW1wJENsdXN0ZXIgPT0gIkxhdGUiKSwKICAgICAgICAgICBzdW0odGVtcCRDbHVzdGVyID09ICJUcmFuc2llbnQiKSkKZGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBjbHVzdGVyLCB2YWx1ZSkKZ2dwbG90KGRhdGEsIGFlcyhmaWxsPWNsdXN0ZXIsIHk9dmFsdWUsIHg9Z3JvdXApKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiLCBzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpCgojIyBMaW5lIHBsb3QKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6c2VsZWN0KGMoNCwgNSwgNiwgNywgOCwgOSkpCnRlbXAudGFsbCA9IHRlbXAgJT4lIHBpdm90X2xvbmdlcigtYygxLCAyKSwgbmFtZXNfdG8gPSAidGltZXBvaW50cyIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCgpnZzEgPSBnZ3Bsb3QodGVtcC50YWxsLAogICAgICAgYWVzKCB4ID0gZmFjdG9yKHRpbWVwb2ludHMsIGxldmVsID0gYygiTUlUIiwgIkVHMSIsICJMRzEiLCAiQVNZTiIpKSwKICAgICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgICBncm91cCA9IGVuc3QsIGNvbCA9IGVuc3QpKSArCiAgZ2VvbV9saW5lKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiQm9iYmllLCBQUk8tc2VxIiwgc3VidGl0bGUgPSAic2VsZWN0ZWQgZ2VuZXMiKSArCiAgeGxhYiAoInRpbWVwb2ludHMiKSArIHlsYWIoInZhbHVlIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCmdnc2F2ZShmaWxlbmFtZSA9IGhlcmUoZmlnRGlyLCAiYm9iYmllX2dlbmVfRXBpTENfZFRBR3ZzRE1TT19ET1dOLnBuZyIpLCBnZzEsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNCwgZHBpID0gMzAwLCB1bml0cyA9ICJpbiIsIGRldmljZSA9ICJwbmciKQoKCiMgRFJBVyBSSUJCT04KCgp0ZW1wLnJpYmJvbiA9IHRpYmJsZSgidGltZXBvaW50cyIgPSBjKCJNSVQiLCAiRUcxIiwgIkxHMSIsICJBU1lOIiksCiAgICAgICAgICAgICAgICAgICAgICAidmFsdWUiID0gYyhtZWFuKHRlbXAkTUlUKSwgbWVhbih0ZW1wJEVHMSksIG1lYW4odGVtcCRMRzEpLCBtZWFuKHRlbXAkQVNZTikpLAogICAgICAgICAgICAgICAgICAgICAgImxvd2VyIiA9IGMobWVhbih0ZW1wJE1JVCkgLSBtYXJnaW5FcnJvcih0ZW1wJE1JVCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbih0ZW1wJEVHMSkgLSBtYXJnaW5FcnJvcih0ZW1wJEVHMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbih0ZW1wJExHMSkgLSBtYXJnaW5FcnJvcih0ZW1wJExHMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbih0ZW1wJEFTWU4pIC0gbWFyZ2luRXJyb3IodGVtcCRBU1lOKSksCiAgICAgICAgICAgICAgICAgICAgICAidXBwZXIiID0gYyhtZWFuKHRlbXAkTUlUKSArIG1hcmdpbkVycm9yKHRlbXAkTUlUKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuKHRlbXAkRUcxKSArIG1hcmdpbkVycm9yKHRlbXAkRUcxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuKHRlbXAkTEcxKSArIG1hcmdpbkVycm9yKHRlbXAkTEcxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuKHRlbXAkQVNZTikgKyBtYXJnaW5FcnJvcih0ZW1wJEFTWU4pKSkKZ2cxID0gZ2dwbG90KHRlbXAucmliYm9uLCBhZXMoeCA9IGZhY3Rvcih0aW1lcG9pbnRzLCBsZXZlbCA9IGMoIk1JVCIsICJFRzEiLCAiTEcxIiwgIkFTWU4iKSksIAogICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsdWUsIGdyb3VwID0gMSkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSwgZmlsbCA9ICJncmV5NzAiLCBhbHBoYSA9IDAuMykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2d0aXRsZSgiQm9iYmllLCBQUk8tc2VxIiwgc3VidGl0bGUgPSAic2VsZWN0ZWQgZ2VuZXMiKSArCiAgeGxhYiAoInRpbWVwb2ludHMiKSArIHlsYWIoInZhbHVlIikgKyB5bGltKDAsIDY1KSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKZ2dzYXZlKGZpbGVuYW1lID0gaGVyZShmaWdEaXIsICJib2JiaWVfZ2VuZV9FcGlMQ19kVEFHdnNETVNPX0RPV05fOTVDSS5wbmciKSwgZ2cxLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSAicG5nIikKCgpgYGAKCiMjI1syLjMzXSBGaW5kaW5nIGNsb3Nlc3QgZW5oYW5jZXIKSGVyZSwgZW5oYW5jZXIgd2lsbCBiZSBkZWZpbmVkIGJ5IEgzSzI3YWMgcGVhawpJdCBtYWtlcyBtb3JlIHNlbmNlIHRvIGluY2x1ZGUgdGhlIGVuaGFuY2VyIHBlYWsgb24gZ2VuZSBib2R5CihzdHJhdGVneSAxKSBleGNsdWRlICstMTBrYiByZWdpb24gZnJvbSBUU1Mgb25seQooc3RyYXRlZ3kgMikgb25seSBjaGVjayB0aGUgRS1QIGxvb3BzIGNhbGxlZCBpbiBNaWNyby1DCiMjIyMjIGJpbmFyeSBncm91cCAtIGV4Y2x1ZGluZyBhbGwgZ2VuZSBib2R5CmBgYHtyfQpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwgZW5zZW1ibCA9IFY2LCBjaHIgPSBWMSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsLCBjaHIsIFRTUykKCmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKCmdlbmUudGIgPC0gZ2VuZS50YiAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsICVpbiUgYyhncm91cDEsIGdyb3VwMikpCmdlbmVzLmdyIDwtIEdSYW5nZXMoCiAgc2VxbmFtZXMgPSBnZW5lLnRiJGNociwKICByYW5nZXMgPSBJUmFuZ2VzKHN0YXJ0ID0gZ2VuZS50YiRUU1MsIGVuZCA9IGdlbmUudGIkVFNTKSwKICBlbnNlbWJsID0gZ2VuZS50YiRlbnNlbWJsCikKCmdlbmVib2R5LnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKGdlbmVib2R5LnRiKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKZ2VuZWJvZHkuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGdlbmVib2R5LnRiKQoKCnBlYWsuSDNLMjdhYyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCnBlYWsuSDNLMjdhYzwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShmcmVhZChoZXJlKHJlZkRpciwgIkdTTTI0Mzg0NzZfRUMtREctMzQ1OC1IM0syN0FDX0FTWU5fMS5uYXJyb3dQZWFrLmJlZCIpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUoY2hyID0gVjEsIHN0YXJ0ID0gKFYyICsgVjMpLzIsIGVuZCA9IChWMiArIFYzKS8yKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChjaHIsIHN0YXJ0LCBlbmQpKQoKIyMjIyMjIyBGaWx0ZXJpbmcgb3V0IHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggdGhlIGdlbmUgYm9keQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoZ2VuZWJvZHkuZ3IsIHBlYWsuSDNLMjdhYykKCiMgSW5kaWNlcyBvZiBwZWFrcyB0aGF0IG92ZXJsYXAgdGhlIFRTUwpvdmVybGFwcGluZ19wZWFrX2luZGljZXMgPC0gdW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXBzKSkKCiMgRXhjbHVkZSBvdmVybGFwcGluZyBwZWFrcwpub25fb3ZlcmxhcHBpbmdfcGVha3MgPC0gcGVhay5IM0syN2FjWy1vdmVybGFwcGluZ19wZWFrX2luZGljZXNdCgoKIyMjIyMjIyBDYWxjdWxhdGluZyBkaXN0YW5jZSB0byBuZWFyZXN0IHBlYWsKbmVhcmVzdF9wZWFrX2luZGljZXMgPC0gbmVhcmVzdChnZW5lcy5nciwgbm9uX292ZXJsYXBwaW5nX3BlYWtzKQpuZWFyZXN0X3BlYWtzIDwtIG5vbl9vdmVybGFwcGluZ19wZWFrc1tuZWFyZXN0X3BlYWtfaW5kaWNlc10KZGlzdGFuY2VzIDwtIGRpc3RhbmNlKGdlbmVzLmdyLCBuZWFyZXN0X3BlYWtzKQoKCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBlbnNlbWJsID0gbWNvbHMoZ2VuZXMuZ3IpJGVuc2VtYmwsCiAgZ2VuZV9jaHIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoZ2VuZXMuZ3IpKSwKICBnZW5lX1RTUyA9IHN0YXJ0KGdlbmVzLmdyKSwKICBwZWFrX2NociA9IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhuZWFyZXN0X3BlYWtzKSksCiAgcGVha19zdGFydCA9IHN0YXJ0KG5lYXJlc3RfcGVha3MpLAogIHBlYWtfZW5kID0gZW5kKG5lYXJlc3RfcGVha3MpLAogIGRpc3RhbmNlID0gZGlzdGFuY2VzCikKCnJlc3VsdHMgPC0gcmVzdWx0cyAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbihlbnNlbWJsICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwMiB+ICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpCgpnZ3Bsb3QocmVzdWx0cywgYWVzKHggPSBncm91cCwgeSA9IGRpc3RhbmNlLCBmaWxsID0gZ3JvdXApKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aCA9IDAuMSwgZmlsbCA9ICJ3aGl0ZSIpICsgdGhlbWVfYncoKSArIGdndGl0bGUoImRpc3RhbmNlIHRvIG5lYXJlc3QgSDNLMjdhYyBwZWFrIGV4Y2x1ZGluZyBnZW5lIGJvZHkiKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMjUwKjEwMDApKQoKICAKYGBgCiMjIyMjIGJpbmFyeSBncm91cCAtIGV4Y2x1ZGluZyBzcGVjaWZpYyBnZW5lIGJvZHkKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLCBlbnNlbWJsID0gVjYsIGNociA9IFYxKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmwsIGNociwgVFNTKSAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsICVpbiUgYyhncm91cDEsIGdyb3VwMikpCmdlbmVzLmdyIDwtIEdSYW5nZXMoCiAgc2VxbmFtZXMgPSBnZW5lLnRiJGNociwKICByYW5nZXMgPSBJUmFuZ2VzKHN0YXJ0ID0gZ2VuZS50YiRUU1MsIGVuZCA9IGdlbmUudGIkVFNTKSwKICBlbnNlbWJsID0gZ2VuZS50YiRlbnNlbWJsCikKCmdlbmVib2R5LnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JSBkcGx5cjo6ZmlsdGVyKFY2ICVpbiUgYyhncm91cDEsIGdyb3VwMikpJT4lIGRwbHlyOjpzZWxlY3QoVjEsIFYyLCBWMykKY29sbmFtZXMoZ2VuZWJvZHkudGIpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQpnZW5lYm9keS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZ2VuZWJvZHkudGIpCgoKIyBTdGVwIDE6IEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBnZW5lIGJvZGllcyBhbmQgcGVha3MKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGdlbmVib2R5LmdyLCBwZWFrLkgzSzI3YWMpCgojIENyZWF0ZSBhIGxpc3QgbWFwcGluZyBlYWNoIGdlbmUgdG8gdGhlIGluZGljZXMgb2YgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCBpdHMgZ2VuZSBib2R5Cm92ZXJsYXBwaW5nX3BlYWtzX3Blcl9nZW5lIDwtIHNwbGl0KHN1YmplY3RIaXRzKG92ZXJsYXBzKSwgcXVlcnlIaXRzKG92ZXJsYXBzKSkKCiMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBsaXN0IHRvIHN0b3JlIHJlc3VsdHMKcmVzdWx0c19saXN0IDwtIHZlY3RvcigibGlzdCIsIGxlbmd0aChnZW5lcy5ncikpCgojIFN0ZXAgMjogRm9yIGVhY2ggZ2VuZSwgZXhjbHVkZSBvdmVybGFwcGluZyBwZWFrcyBhbmQgZmluZCB0aGUgbmVhcmVzdCBwZWFrIHRvIGl0cyBUU1MKZm9yIChpIGluIHNlcV9hbG9uZyhnZW5lcy5ncikpIHsKICBnZW5lIDwtIGdlbmVzLmdyW2ldCiAgCiAgIyBHZXQgaW5kaWNlcyBvZiBwZWFrcyBvdmVybGFwcGluZyB3aXRoIHRoaXMgZ2VuZSdzIGJvZHkKICBvdmVybGFwcGluZ19wZWFrX2luZGljZXMgPC0gb3ZlcmxhcHBpbmdfcGVha3NfcGVyX2dlbmVbW2FzLmNoYXJhY3RlcihpKV1dCiAgCiAgIyBFeGNsdWRlIG92ZXJsYXBwaW5nIHBlYWtzIGZvciB0aGlzIGdlbmUKICBpZiAoIWlzLm51bGwob3ZlcmxhcHBpbmdfcGVha19pbmRpY2VzKSkgewogICAgcGVha3NfdG9fY29uc2lkZXIgPC0gcGVhay5IM0syN2FjWy1vdmVybGFwcGluZ19wZWFrX2luZGljZXNdCiAgfSBlbHNlIHsKICAgIHBlYWtzX3RvX2NvbnNpZGVyIDwtIHBlYWsuSDNLMjdhYwogIH0KICAKICAjIEZpbmQgdGhlIG5lYXJlc3QgcGVhayB0byB0aGUgVFNTIG9mIHRoaXMgZ2VuZQogIG5lYXJlc3RfcGVha19pbmRleCA8LSBuZWFyZXN0KGdlbmUsIHBlYWtzX3RvX2NvbnNpZGVyKQogIAogIGlmIChpcy5uYShuZWFyZXN0X3BlYWtfaW5kZXgpKSB7CiAgICAjIE5vIHBlYWtzIGZvdW5kOyBzZXQgTkEgdmFsdWVzCiAgICByZXN1bHRzX2xpc3RbW2ldXSA8LSBkYXRhLmZyYW1lKAogICAgICBlbnNlbWJsID0gbWNvbHMoZ2VuZSkkZW5zZW1ibCwKICAgICAgZ2VuZV9jaHIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoZ2VuZSkpLAogICAgICBnZW5lX1RTUyA9IHN0YXJ0KGdlbmUpLAogICAgICBwZWFrX2NociA9IE5BLAogICAgICBwZWFrX3N0YXJ0ID0gTkEsCiAgICAgIHBlYWtfZW5kID0gTkEsCiAgICAgIGRpc3RhbmNlID0gTkEKICAgICkKICB9IGVsc2UgewogICAgbmVhcmVzdF9wZWFrIDwtIHBlYWtzX3RvX2NvbnNpZGVyW25lYXJlc3RfcGVha19pbmRleF0KICAgIGRpc3QgPC0gZGlzdGFuY2UoZ2VuZSwgbmVhcmVzdF9wZWFrKQogICAgCiAgICByZXN1bHRzX2xpc3RbW2ldXSA8LSBkYXRhLmZyYW1lKAogICAgICBlbnNlbWJsID0gbWNvbHMoZ2VuZSkkZW5zZW1ibCwKICAgICAgZ2VuZV9jaHIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoZ2VuZSkpLAogICAgICBnZW5lX1RTUyA9IHN0YXJ0KGdlbmUpLAogICAgICBwZWFrX2NociA9IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhuZWFyZXN0X3BlYWspKSwKICAgICAgcGVha19zdGFydCA9IHN0YXJ0KG5lYXJlc3RfcGVhayksCiAgICAgIHBlYWtfZW5kID0gZW5kKG5lYXJlc3RfcGVhayksCiAgICAgIGRpc3RhbmNlID0gZGlzdAogICAgKQogIH0KfQoKIyBDb21iaW5lIHJlc3VsdHMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCnJlc3VsdHMgPC0gZG8uY2FsbChyYmluZCwgcmVzdWx0c19saXN0KQoKIyBBZGQgZ3JvdXAgaW5mb3JtYXRpb24KcmVzdWx0cyA8LSByZXN1bHRzICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKAogIGVuc2VtYmwgJWluJSBncm91cDEgfiAiZ3JvdXAxIiwKICBlbnNlbWJsICVpbiUgZ3JvdXAyIH4gImdyb3VwMiIsCiAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KKSkKCiMgUGxvdHRpbmcKZ2dwbG90KHJlc3VsdHMsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaXN0YW5jZSwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fdmlvbGluKCkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIHdpZHRoID0gMC4xLCBmaWxsID0gIndoaXRlIikgKwogIHRoZW1lX2J3KCkgKwogIGdndGl0bGUoIkRpc3RhbmNlIHRvIE5lYXJlc3QgSDNLMjdhYyBQZWFrIEV4Y2x1ZGluZyBHZW5lIEJvZHkgT3ZlcmxhcHMiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDUwICogMTAwMCkpCmBgYAoKIyMjIyMgYmluYXJ5IGdyb3VwIC0gZXhjbHVkaW5nIGFsbCBUU1MgKy0gMTBrYgpgYGB7cn0KZ2VuZS50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMyksIGVuc2VtYmwgPSBWNiwgY2hyID0gVjEpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibCwgY2hyLCBUU1MpCgpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCgpnZW5lLnRiIDwtIGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGMoZ3JvdXAxLCBncm91cDIpKQpnZW5lcy5nciA8LSBHUmFuZ2VzKAogIHNlcW5hbWVzID0gZ2VuZS50YiRjaHIsCiAgcmFuZ2VzID0gSVJhbmdlcyhzdGFydCA9IGdlbmUudGIkVFNTLCBlbmQgPSBnZW5lLnRiJFRTUyksCiAgZW5zZW1ibCA9IGdlbmUudGIkZW5zZW1ibAopCgpnZW5lYm9keS50YiA8LSBnZW5lLnRiICU+JSBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gVFNTLTEwKjEwMDAsIGVuZCA9IFRTUyArIDEwKjEwMDApICU+JQogIGRwbHlyOjpzZWxlY3QoY2hyLCBzdGFydCwgZW5kKQoKZ2VuZWJvZHkuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGdlbmVib2R5LnRiKQoKCnBlYWsuSDNLMjdhYyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCiMgcGVhay5IM0syN2FjPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGZyZWFkKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpICU+JSAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6bXV0YXRlKGNociA9IFYxLCBzdGFydCA9IChWMiArIFYzKS8yLCBlbmQgPSAoVjIgKyBWMykvMikgJT4lCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChjaHIsIHN0YXJ0LCBlbmQpKQoKIyMjIyMjIyBGaWx0ZXJpbmcgb3V0IHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggdGhlIGdlbmUgYm9keQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoZ2VuZWJvZHkuZ3IsIHBlYWsuSDNLMjdhYykKCiMgSW5kaWNlcyBvZiBwZWFrcyB0aGF0IG92ZXJsYXAgdGhlIFRTUwpvdmVybGFwcGluZ19wZWFrX2luZGljZXMgPC0gdW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXBzKSkKCiMgRXhjbHVkZSBvdmVybGFwcGluZyBwZWFrcwpub25fb3ZlcmxhcHBpbmdfcGVha3MgPC0gcGVhay5IM0syN2FjWy1vdmVybGFwcGluZ19wZWFrX2luZGljZXNdCgoKIyMjIyMjIyBDYWxjdWxhdGluZyBkaXN0YW5jZSB0byBuZWFyZXN0IHBlYWsKbmVhcmVzdF9wZWFrX2luZGljZXMgPC0gbmVhcmVzdChnZW5lcy5nciwgbm9uX292ZXJsYXBwaW5nX3BlYWtzKQpuZWFyZXN0X3BlYWtzIDwtIG5vbl9vdmVybGFwcGluZ19wZWFrc1tuZWFyZXN0X3BlYWtfaW5kaWNlc10KZGlzdGFuY2VzIDwtIGRpc3RhbmNlKGdlbmVzLmdyLCBuZWFyZXN0X3BlYWtzKQoKCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBlbnNlbWJsID0gbWNvbHMoZ2VuZXMuZ3IpJGVuc2VtYmwsCiAgZ2VuZV9jaHIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoZ2VuZXMuZ3IpKSwKICBnZW5lX1RTUyA9IHN0YXJ0KGdlbmVzLmdyKSwKICBwZWFrX2NociA9IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhuZWFyZXN0X3BlYWtzKSksCiAgcGVha19zdGFydCA9IHN0YXJ0KG5lYXJlc3RfcGVha3MpLAogIHBlYWtfZW5kID0gZW5kKG5lYXJlc3RfcGVha3MpLAogIGRpc3RhbmNlID0gZGlzdGFuY2VzCikKCnJlc3VsdHMgPC0gcmVzdWx0cyAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbihlbnNlbWJsICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwMiB+ICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpCgpnZ3Bsb3QocmVzdWx0cywgYWVzKHggPSBncm91cCwgeSA9IGRpc3RhbmNlLCBmaWxsID0gZ3JvdXApKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aCA9IDAuMSwgZmlsbCA9ICJ3aGl0ZSIpICsgdGhlbWVfYncoKSArIGdndGl0bGUoImRpc3RhbmNlIHRvIG5lYXJlc3QgSDNLMjdhYyBwZWFrIGV4Y2x1ZGluZyBnZW5lIGJvZHkiKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMjUwKjEwMDApKQoKICAKYGBgCgojIyMjIyBiaW5hcnkgZ3JvdXAgLSBleGNsdWRpbmcgc3BlY2lmaWMgVFNTICstIDEwIGtiCmBgYHtyfQpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCgpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwgZW5zZW1ibCA9IFY2LCBjaHIgPSBWMSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsLCBjaHIsIFRTUykgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGMoZ3JvdXAxLCBncm91cDIpKQpnZW5lcy5nciA8LSBHUmFuZ2VzKAogIHNlcW5hbWVzID0gZ2VuZS50YiRjaHIsCiAgcmFuZ2VzID0gSVJhbmdlcyhzdGFydCA9IGdlbmUudGIkVFNTLCBlbmQgPSBnZW5lLnRiJFRTUyksCiAgZW5zZW1ibCA9IGdlbmUudGIkZW5zZW1ibAopCgpnZW5lYm9keS50YiA8LSBnZW5lLnRiICU+JSBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gVFNTLTEwKjEwMDAsIGVuZCA9IFRTUyArIDEwKjEwMDApICU+JQogIGRwbHlyOjpzZWxlY3QoY2hyLCBzdGFydCwgZW5kKQpnZW5lYm9keS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZ2VuZWJvZHkudGIpCgpwZWFrLkgzSzI3YWMgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIkdTTTI0Mzg0NzZfRUMtREctMzQ1OC1IM0syN0FDX0FTWU5fMS5uYXJyb3dQZWFrLmJlZCIpKQoKCiMgU3RlcCAxOiBGaW5kIG92ZXJsYXBzIGJldHdlZW4gZ2VuZSBib2RpZXMgYW5kIHBlYWtzCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhnZW5lYm9keS5nciwgcGVhay5IM0syN2FjKQoKIyBDcmVhdGUgYSBsaXN0IG1hcHBpbmcgZWFjaCBnZW5lIHRvIHRoZSBpbmRpY2VzIG9mIHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggaXRzIGdlbmUgYm9keQpvdmVybGFwcGluZ19wZWFrc19wZXJfZ2VuZSA8LSBzcGxpdChzdWJqZWN0SGl0cyhvdmVybGFwcyksIHF1ZXJ5SGl0cyhvdmVybGFwcykpCgojIEluaXRpYWxpemUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSByZXN1bHRzCnJlc3VsdHNfbGlzdCA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGgoZ2VuZXMuZ3IpKQoKIyBTdGVwIDI6IEZvciBlYWNoIGdlbmUsIGV4Y2x1ZGUgb3ZlcmxhcHBpbmcgcGVha3MgYW5kIGZpbmQgdGhlIG5lYXJlc3QgcGVhayB0byBpdHMgVFNTCmZvciAoaSBpbiBzZXFfYWxvbmcoZ2VuZXMuZ3IpKSB7CiAgZ2VuZSA8LSBnZW5lcy5ncltpXQogIAogICMgR2V0IGluZGljZXMgb2YgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCB0aGlzIGdlbmUncyBib2R5CiAgb3ZlcmxhcHBpbmdfcGVha19pbmRpY2VzIDwtIG92ZXJsYXBwaW5nX3BlYWtzX3Blcl9nZW5lW1thcy5jaGFyYWN0ZXIoaSldXQogIAogICMgRXhjbHVkZSBvdmVybGFwcGluZyBwZWFrcyBmb3IgdGhpcyBnZW5lCiAgaWYgKCFpcy5udWxsKG92ZXJsYXBwaW5nX3BlYWtfaW5kaWNlcykpIHsKICAgIHBlYWtzX3RvX2NvbnNpZGVyIDwtIHBlYWsuSDNLMjdhY1stb3ZlcmxhcHBpbmdfcGVha19pbmRpY2VzXQogIH0gZWxzZSB7CiAgICBwZWFrc190b19jb25zaWRlciA8LSBwZWFrLkgzSzI3YWMKICB9CiAgCiAgIyBGaW5kIHRoZSBuZWFyZXN0IHBlYWsgdG8gdGhlIFRTUyBvZiB0aGlzIGdlbmUKICBuZWFyZXN0X3BlYWtfaW5kZXggPC0gbmVhcmVzdChnZW5lLCBwZWFrc190b19jb25zaWRlcikKICAKICBpZiAoaXMubmEobmVhcmVzdF9wZWFrX2luZGV4KSkgewogICAgIyBObyBwZWFrcyBmb3VuZDsgc2V0IE5BIHZhbHVlcwogICAgcmVzdWx0c19saXN0W1tpXV0gPC0gZGF0YS5mcmFtZSgKICAgICAgZW5zZW1ibCA9IG1jb2xzKGdlbmUpJGVuc2VtYmwsCiAgICAgIGdlbmVfY2hyID0gYXMuY2hhcmFjdGVyKHNlcW5hbWVzKGdlbmUpKSwKICAgICAgZ2VuZV9UU1MgPSBzdGFydChnZW5lKSwKICAgICAgcGVha19jaHIgPSBOQSwKICAgICAgcGVha19zdGFydCA9IE5BLAogICAgICBwZWFrX2VuZCA9IE5BLAogICAgICBkaXN0YW5jZSA9IE5BCiAgICApCiAgfSBlbHNlIHsKICAgIG5lYXJlc3RfcGVhayA8LSBwZWFrc190b19jb25zaWRlcltuZWFyZXN0X3BlYWtfaW5kZXhdCiAgICBkaXN0IDwtIGRpc3RhbmNlKGdlbmUsIG5lYXJlc3RfcGVhaykKICAgIAogICAgcmVzdWx0c19saXN0W1tpXV0gPC0gZGF0YS5mcmFtZSgKICAgICAgZW5zZW1ibCA9IG1jb2xzKGdlbmUpJGVuc2VtYmwsCiAgICAgIGdlbmVfY2hyID0gYXMuY2hhcmFjdGVyKHNlcW5hbWVzKGdlbmUpKSwKICAgICAgZ2VuZV9UU1MgPSBzdGFydChnZW5lKSwKICAgICAgcGVha19jaHIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMobmVhcmVzdF9wZWFrKSksCiAgICAgIHBlYWtfc3RhcnQgPSBzdGFydChuZWFyZXN0X3BlYWspLAogICAgICBwZWFrX2VuZCA9IGVuZChuZWFyZXN0X3BlYWspLAogICAgICBkaXN0YW5jZSA9IGRpc3QKICAgICkKICB9Cn0KCiMgQ29tYmluZSByZXN1bHRzIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpyZXN1bHRzIDwtIGRvLmNhbGwocmJpbmQsIHJlc3VsdHNfbGlzdCkKCiMgQWRkIGdyb3VwIGluZm9ybWF0aW9uCnJlc3VsdHMgPC0gcmVzdWx0cyAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbigKICBlbnNlbWJsICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgZW5zZW1ibCAlaW4lIGdyb3VwMiB+ICJncm91cDIiLAogIFRSVUUgfiBOQV9jaGFyYWN0ZXJfCikpCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gZ3JvdXAxKSApJGRpc3RhbmNlCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09IGdyb3VwMikgKSRkaXN0YW5jZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCmdldFB2YWxXaWxjb3gocmVzdWx0cywgImdyb3VwMSIsICJncm91cDIiKQojIFBsb3R0aW5nCmdncGxvdChyZXN1bHRzLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlzdGFuY2UsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aCA9IDAuMSwgZmlsbCA9ICJ3aGl0ZSIpICsKICB0aGVtZV9idygpICsKICBnZ3RpdGxlKCJEaXN0YW5jZSB0byBOZWFyZXN0IEgzSzI3YWMgUGVhayBFeGNsdWRpbmcgR2VuZSBCb2R5IE92ZXJsYXBzIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA1MCAqIDEwMDApKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgCmBgYAoKIyMjIyMgT25seSBsaW1pdGluZyB0byBFLVAgbG9vcHMgZnJvbSBNaWNyby1DCmBgYHtyfQoKZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgoKCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1wZV9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSAwLjIpICU+JQogIGRwbHlyOjpmaWx0ZXIoQW5ubzIgPT0gIlAtRSIpCgp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgdW5uZXN0KGdlbmUpCgpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwgZW5zZW1ibCA9IFY2LCBjaHIgPSBWMSkgJT4lCiAgZHBseXI6OnNlbGVjdChlbnNlbWJsLCBjaHIsIFRTUykKCnRlbXAgPC0gZHBseXI6OmxlZnRfam9pbih0ZW1wLCBnZW5lLnRiLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmwiKSkKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShjZW50ZXIxID0gKHN0YXJ0MSArIGVuZDEpLzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXIyID0gKHN0YXJ0MiArIGVuZDIpLzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0YW5jZTEgPSBhYnMoVFNTLWNlbnRlcjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGFuY2UyID0gYWJzKFRTUy1jZW50ZXIyKSkgJT4lCiAgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHBtYXgoZGlzdGFuY2UxLCBkaXN0YW5jZTIpKQoKdGVtcCA8LSB0ZW1wICU+JSBncm91cF9ieShnZW5lKSAlPiUgc3VtbWFyaXplKG1pbl9lbmhfZGlzdGFuY2UgPSBtaW4oZGlzdGFuY2UpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKGdlbmUgJWluJSBncm91cDEgfiAiZ3JvdXAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBncm91cDIgfiAiZ3JvdXAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgpnZ3Bsb3QodGVtcCwgYWVzKHggPSBncm91cCwgeSA9IG1pbl9lbmhfZGlzdGFuY2UsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV92aW9saW4oKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjEsIGZpbGwgPSAid2hpdGUiKSArCiAgdGhlbWVfYncoKSArCiAgZ2d0aXRsZSgiRGlzdGFuY2UgdG8gTmVhcmVzdCBFbmhhbmNlciBmcm8gRS1QIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMTAwMCAqIDEwMDApKQoKYGBgCgoKCiMjIyBbMi4yNF0gKFdPUktJTkcgT04pQ2hlY2tpbmcgdGhlIHBlcmNlbnRhZ2Ugb2Ygbm9uLWltcG9ydGFudCBsb29wcwpJZGVhOiBoYXZpbmcgb25lIG5vbi1wZXJ0dXJiZWQgcmVnIGxvb3BzIGNvdWxkIGJlIGVub3VnaC4KYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yKQoKCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShzaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIHNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgc2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgc2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQoKZ2VuZUFubm9EYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGMobG9vcC51cCRpZCwgbG9vcC5ubyRpZCwgbG9vcC5kb3duJGlkKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb29wVHlwZSA9IGNhc2Vfd2hlbihpZCAlaW4lIGMobG9vcC51cCRpZCwgbG9vcC5ubyRpZCkgfiAiaW5zZW5zaXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgJWluJSBjKGxvb3AuZG93biRpZCkgfiAic2Vuc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpCgpkYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChnZW5lLCBpZCwgbG9vcFR5cGUpICU+JSB1bm5lc3QoZ2VuZSkgJT4lCiAgZ3JvdXBfYnkoZ2VuZSkgJT4lIHN1bW1hcml6ZSgKICAgIGluc2Vuc2l0aXZlID0gc3VtKGxvb3BUeXBlID09ICJpbnNlbnNpdGl2ZSIsIG5hLnJtID0gVFJVRSksCiAgICBzZW5zaXRpdmUgPSBzdW0obG9vcFR5cGUgPT0gInNlbnNpdGl2ZSIsIG5hLnJtID0gVFJVRSkpCgoKCiMjIwoKZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpnZW5lR3JvdXAgPC0gdGliYmxlKGdyb3VwID0gYyhyZXAoImdyb3VwMSIsIGxlbmd0aChncm91cDEpKSwgcmVwKCJncm91cDIiLCBsZW5ndGgoZ3JvdXAyKSkpLAogICAgICAgICAgICAgICAgICAgIGdlbmUgPSBjKGdyb3VwMSwgZ3JvdXAyKSkKCmRhdGEgPC0gbGVmdF9qb2luKGdlbmVHcm91cCwgZGF0YSwgYnkgPSBjKCJnZW5lIikpICU+JSBkcGx5cjo6bXV0YXRlKG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+cmVwbGFjZV9uYSguLCAwKSkpKQoKCiMjIwpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUocHJlc2VuY2VPZlJldGFpbmVkID0gaWZfZWxzZShpbnNlbnNpdGl2ZSA+IDAsICJZRVMiLCAiTk8iKSwKICAgICAgICAgICAgICAgICAgICAgICBwZXJjT2ZSZXRhaW5lZCA9IGlmX2Vsc2UoaW5zZW5zaXRpdmUgKyBzZW5zaXRpdmUgPT0gMCwgMCwgMTAwKmluc2Vuc2l0aXZlLyhpbnNlbnNpdGl2ZSArIHNlbnNpdGl2ZSkpKQoKCiMjIwpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IHBlcmNPZlJldGFpbmVkLCBmaWxsID0gZ3JvdXApKSArIGdlb21fdmlvbGluKCkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aCA9IDAuMSwgZmlsbCA9ICJ3aGl0ZSIpICsgdGhlbWVfYncoKQoKCiMjIyBTdGFja2VkIGJhcnBsb3QKZ3JvdXAgPC0gYygiZ3JvdXAxIiwgImdyb3VwMSIsICJncm91cDIiLCAiZ3JvdXAyIikKcHJlc2VuY2VPZlJldGFpbmVkIDwtIHJlcChjKCJZRVMiLCAiTk8iKSwgMikKcHJlc2VuY2VPZlJldGFpbmVkIDwtIGZhY3RvciAocHJlc2VuY2VPZlJldGFpbmVkLCBsZXZlbHMgPSBjKCJZRVMiLCAiTk8iKSkKdmFsdWUgPC0gYyhucm93KGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwMSIsIHByZXNlbmNlT2ZSZXRhaW5lZCA9PSAiWUVTIikpLAogICAgICAgICAgIG5yb3coZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAxIiwgcHJlc2VuY2VPZlJldGFpbmVkID09ICJOTyIpKSwKICAgICAgICAgICBucm93KGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwMiIsIHByZXNlbmNlT2ZSZXRhaW5lZCA9PSAiWUVTIikpLAogICAgICAgICAgIG5yb3coZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAyIiwgcHJlc2VuY2VPZlJldGFpbmVkID09ICJOTyIpKSkKcGxvdERhdGEgPC0gZGF0YS5mcmFtZShncm91cCwgcHJlc2VuY2VPZlJldGFpbmVkLCB2YWx1ZSkKCmdncGxvdChwbG90RGF0YSwgYWVzKGZpbGw9cHJlc2VuY2VPZlJldGFpbmVkLCB5PXZhbHVlLCB4PWdyb3VwKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKQoKCmBgYAoKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLXBlX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMikKCgpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpICU+JQogIGRwbHlyOjptdXRhdGUoc2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBzaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShzaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIHNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShzaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIHNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKCmdlbmVBbm5vRGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBjKGxvb3AudXAkaWQsIGxvb3Aubm8kaWQsIGxvb3AuZG93biRpZCkpICU+JQogIGRwbHlyOjptdXRhdGUobG9vcFR5cGUgPSBjYXNlX3doZW4oaWQgJWluJSBjKGxvb3AudXAkaWQsIGxvb3Aubm8kaWQpIH4gImluc2Vuc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkICVpbiUgYyhsb29wLmRvd24kaWQpIH4gInNlbnNpdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkEpKQoKZGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZ2VuZSwgaWQsIGxvb3BUeXBlKSAlPiUgdW5uZXN0KGdlbmUpICU+JQogIGdyb3VwX2J5KGdlbmUpICU+JSBzdW1tYXJpemUoCiAgICBpbnNlbnNpdGl2ZSA9IHN1bShsb29wVHlwZSA9PSAiaW5zZW5zaXRpdmUiLCBuYS5ybSA9IFRSVUUpLAogICAgc2Vuc2l0aXZlID0gc3VtKGxvb3BUeXBlID09ICJzZW5zaXRpdmUiLCBuYS5ybSA9IFRSVUUpKQoKCgojIyMKCmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKZ2VuZUdyb3VwIDwtIHRpYmJsZShncm91cCA9IGMocmVwKCJncm91cDEiLCBsZW5ndGgoZ3JvdXAxKSksIHJlcCgiZ3JvdXAyIiwgbGVuZ3RoKGdyb3VwMikpKSwKICAgICAgICAgICAgICAgICAgICBnZW5lID0gYyhncm91cDEsIGdyb3VwMikpCgpkYXRhIDwtIGxlZnRfam9pbihnZW5lR3JvdXAsIGRhdGEsIGJ5ID0gYygiZ2VuZSIpKSAlPiUgZHBseXI6Om11dGF0ZShtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfnJlcGxhY2VfbmEoLiwgMCkpKSkKCgojIyMKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKHByZXNlbmNlT2ZSZXRhaW5lZCA9IGlmX2Vsc2UoaW5zZW5zaXRpdmUgPiAwLCAiWUVTIiwgIk5PIiksCiAgICAgICAgICAgICAgICAgICAgICAgcGVyY09mUmV0YWluZWQgPSBpZl9lbHNlKGluc2Vuc2l0aXZlICsgc2Vuc2l0aXZlID09IDAsIDAsIDEwMCppbnNlbnNpdGl2ZS8oaW5zZW5zaXRpdmUgKyBzZW5zaXRpdmUpKSkKCgojIyMKZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBwZXJjT2ZSZXRhaW5lZCwgZmlsbCA9IGdyb3VwKSkgKyBnZW9tX3Zpb2xpbigpICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjA1LCBmaWxsID0gIndoaXRlIikgKyB0aGVtZV9idygpCgoKIyMjIFN0YWNrZWQgYmFycGxvdApncm91cCA8LSBjKCJncm91cDEiLCAiZ3JvdXAxIiwgImdyb3VwMiIsICJncm91cDIiKQpwcmVzZW5jZU9mUmV0YWluZWQgPC0gcmVwKGMoIllFUyIsICJOTyIpLCAyKQpwcmVzZW5jZU9mUmV0YWluZWQgPC0gZmFjdG9yIChwcmVzZW5jZU9mUmV0YWluZWQsIGxldmVscyA9IGMoIllFUyIsICJOTyIpKQp2YWx1ZSA8LSBjKG5yb3coZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAxIiwgcHJlc2VuY2VPZlJldGFpbmVkID09ICJZRVMiKSksCiAgICAgICAgICAgbnJvdyhkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJncm91cDEiLCBwcmVzZW5jZU9mUmV0YWluZWQgPT0gIk5PIikpLAogICAgICAgICAgIG5yb3coZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAyIiwgcHJlc2VuY2VPZlJldGFpbmVkID09ICJZRVMiKSksCiAgICAgICAgICAgbnJvdyhkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJncm91cDIiLCBwcmVzZW5jZU9mUmV0YWluZWQgPT0gIk5PIikpKQpwbG90RGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwLCBwcmVzZW5jZU9mUmV0YWluZWQsIHZhbHVlKQoKZ2dwbG90KHBsb3REYXRhLCBhZXMoZmlsbD1wcmVzZW5jZU9mUmV0YWluZWQsIHk9dmFsdWUsIHg9Z3JvdXApKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiLCBzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpCgoKYGBgCgojIyMgWzIuMjVdIE9icy9FeHAgbG9vcHMKCgojIyMjIE1lcmdpbmcgb2JzL2V4cCBzY29yZXMgZnJvbSBkaWZmZXJlbnQgcmVzb2x1dGlvbiAmIHNhbXBsZXMKIyMjIyMgRzEKYGBge3J9Cmxvb3BzIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfc2NvcmUudHN2IikpCgpzYW1wbGUgPC0gIkcxLkRNU08uTWVyZ2VkIgpmb3Ioc2FtcGxlIGluIGMoIkcxLkRNU08uTWVyZ2VkIiwgIkcxLmRUQUcuTWVyZ2VkIiwgIkcxLkE0ODUuTWVyZ2VkIikpewogIHRlbXAuMjVrYiA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiXzI1a2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC4yNWtiKSA8LSBjKCJjaHJvbTEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyb20yIiwgInN0YXJ0MiIsICJlbmQyIiwgImlkIiwgIm9icyIsICJvYnNleHAiKQogIAogIHRlbXAuMTBrYiA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiXzEwa2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC4xMGtiKSA8LSBjKCJjaHJvbTEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyb20yIiwgInN0YXJ0MiIsICJlbmQyIiwgImlkIiwgIm9icyIsICJvYnNleHAiKQogIAogIHRlbXAuNWtiIDwtZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlXyIsIHNhbXBsZSwgIl81a2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC41a2IpIDwtIGMoImNocm9tMSIsICJzdGFydDEiLCAiZW5kMSIsICJjaHJvbTIiLCAic3RhcnQyIiwgImVuZDIiLCAiaWQiLCAib2JzIiwgIm9ic2V4cCIpCiAgCiAgdGVtcCA8LSBiaW5kX3Jvd3ModGVtcC4yNWtiLCB0ZW1wLjEwa2IsIHRlbXAuNWtiKQogIGZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiLnRzdiIpKSwgc2VwID0gIlx0IikKfQoKCnRlbXAuRE1TTyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImxvb3BTY29yZV9HMS5ETVNPLk1lcmdlZC50c3YiKSkgJT4lCiAgZHBseXI6OnNlbGVjdChpZCwgb2JzLCBvYnNleHApCmNvbG5hbWVzKHRlbXAuRE1TTykgPC0gYygiaWQiLCAib2JzX0RNU08iLCAib2JzZXhwX0RNU08iKQp0ZW1wLmRUQUcgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJsb29wU2NvcmVfRzEuZFRBRy5NZXJnZWQudHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoaWQsIG9icywgb2JzZXhwKQpjb2xuYW1lcyh0ZW1wLmRUQUcpIDwtIGMoImlkIiwgIm9ic19kVEFHIiwgIm9ic2V4cF9kVEFHIikKdGVtcC5BNDg1IDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAibG9vcFNjb3JlX0cxLkE0ODUuTWVyZ2VkLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGlkLCBvYnMsIG9ic2V4cCkKY29sbmFtZXModGVtcC5BNDg1KSA8LSBjKCJpZCIsICJvYnNfQTQ4NSIsICJvYnNleHBfQTQ4NSIpCgpsb29wc19vZSA8LSBmdWxsX2pvaW4oZnVsbF9qb2luKHRlbXAuRE1TTywgdGVtcC5kVEFHLCBieSA9ICJpZCIpLAogICAgICAgICAgdGVtcC5BNDg1LCBieSA9ICJpZCIpICU+JQogIGRwbHlyOjptdXRhdGUob2VGQ19kVEFHX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIE5BLCBvYnNleHBfZFRBRy9vYnNleHBfRE1TTyksCiAgICAgICAgICAgICAgICBvZUZDX0E0ODVfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgTkEsIG9ic2V4cF9BNDg1L29ic2V4cF9ETVNPKSkKCmZ3cml0ZShsb29wc19vZSwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSwgc2VwID0gIlx0IikKYGBgCgojIyMjIyBBc3luYwpgYGB7cn0KbG9vcHMgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZS50c3YiKSkKCmZvcihzYW1wbGUgaW4gYygiQXN5bmMuVVQiLCAiQXN5bmMuQUlEIikpewogIHRlbXAuMjVrYiA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiXzI1a2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC4yNWtiKSA8LSBjKCJjaHJvbTEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyb20yIiwgInN0YXJ0MiIsICJlbmQyIiwgImlkIiwgIm9icyIsICJvYnNleHAiKQogIAogIHRlbXAuMTBrYiA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiXzEwa2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC4xMGtiKSA8LSBjKCJjaHJvbTEiLCAic3RhcnQxIiwgImVuZDEiLCAiY2hyb20yIiwgInN0YXJ0MiIsICJlbmQyIiwgImlkIiwgIm9icyIsICJvYnNleHAiKQogIAogIHRlbXAuNWtiIDwtZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlXyIsIHNhbXBsZSwgIl81a2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGlkLCBvYnNlcnZlZCwgIk8vRSIpCiAgY29sbmFtZXModGVtcC41a2IpIDwtIGMoImNocm9tMSIsICJzdGFydDEiLCAiZW5kMSIsICJjaHJvbTIiLCAic3RhcnQyIiwgImVuZDIiLCAiaWQiLCAib2JzIiwgIm9ic2V4cCIpCiAgCiAgdGVtcCA8LSBiaW5kX3Jvd3ModGVtcC4yNWtiLCB0ZW1wLjEwa2IsIHRlbXAuNWtiKQogIGZ3cml0ZSh0ZW1wLCBoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfIiwgc2FtcGxlLCAiLnRzdiIpKSwgc2VwID0gIlx0IikKfQoKCnRlbXAuVVQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJsb29wU2NvcmVfQXN5bmMuVVQudHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoaWQsIG9icywgb2JzZXhwKQpjb2xuYW1lcyh0ZW1wLlVUKSA8LSBjKCJpZCIsICJvYnNfVVQiLCAib2JzZXhwX1VUIikKdGVtcC5BSUQgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJsb29wU2NvcmVfQXN5bmMuQUlELnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGlkLCBvYnMsIG9ic2V4cCkKY29sbmFtZXModGVtcC5BSUQpIDwtIGMoImlkIiwgIm9ic19BSUQiLCAib2JzZXhwX0FJRCIpCgpsb29wc19vZSA8LSBmdWxsX2pvaW4odGVtcC5VVCwgdGVtcC5BSUQsIGJ5ID0gImlkIikgJT4lCiAgZHBseXI6Om11dGF0ZShvZUZDX0FJRF9VVCA9IGlmX2Vsc2Uob2JzZXhwX1VUID09IDAsIE5BLCBvYnNleHBfQUlEL29ic2V4cF9VVCkpCgpmd3JpdGUobG9vcHNfb2UsIGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cF9Bc3luYy50c3YiKSksIHNlcCA9ICJcdCIpCmBgYAoKIyMjIyBNZXJnaW5nIG9icy9leHAgcGVyIHJlc29sdXRpb24KT25seSB0aGUgbG9vcHMgdGhhdCBtYWRlIHRvIGNvbnNlbnN1cyBsb29wcyBhcmUgY29uc2lkZXJlZAojIyMjIyBHMQpgYGB7cn0KbG9vcHMgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19zY29yZS50c3YiKSkKCnJlcyA8LSAyNQoKZm9yIChyZXMgaW4gYygyNSwgMTAsIDUpKXsKICAKICB0ZW1wLkRNU08gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX0cxLkRNU08uTWVyZ2VkXyIsIHJlcywgImtiLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBlbmQxIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKGNocm9tMSwgYmluU2l6ZSwgc3RhcnQxLCBzdGFydDIsIHNlcCA9ICJfIikpICU+JQogICAgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3BzJGlkKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoaWQsIG9ic2VydmVkLCAiTy9FIikKICBjb2xuYW1lcyh0ZW1wLkRNU08pIDwtIGMoImlkIiwgIm9ic19ETVNPIiwgIm9ic2V4cF9ETVNPIikKICAKICB0ZW1wLmRUQUcgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX0cxLmRUQUcuTWVyZ2VkXyIsIHJlcywgImtiLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBlbmQxIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKGNocm9tMSwgYmluU2l6ZSwgc3RhcnQxLCBzdGFydDIsIHNlcCA9ICJfIikpICU+JQogICAgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3BzJGlkKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoaWQsIG9ic2VydmVkLCAiTy9FIikKICBjb2xuYW1lcyh0ZW1wLmRUQUcpIDwtIGMoImlkIiwgIm9ic19kVEFHIiwgIm9ic2V4cF9kVEFHIikKICAKICB0ZW1wLkE0ODUgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX0cxLkE0ODUuTWVyZ2VkXyIsIHJlcywgImtiLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBlbmQxIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKGNocm9tMSwgYmluU2l6ZSwgc3RhcnQxLCBzdGFydDIsIHNlcCA9ICJfIikpICU+JQogICAgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3BzJGlkKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoaWQsIG9ic2VydmVkLCAiTy9FIikKICBjb2xuYW1lcyh0ZW1wLkE0ODUpIDwtIGMoImlkIiwgIm9ic19BNDg1IiwgIm9ic2V4cF9BNDg1IikKICAKICB0ZW1wIDwtIGZ1bGxfam9pbihmdWxsX2pvaW4odGVtcC5ETVNPLCB0ZW1wLmRUQUcsIGJ5ID0gYygiaWQiKSksIHRlbXAuQTQ4NSwgYnkgPSBjKCJpZCIpKSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKG9lRkNfZFRBR19ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBOQSwgb2JzZXhwX2RUQUcvb2JzZXhwX0RNU08pLAogICAgICAgICAgICAgICAgICBvZUZDX0E0ODVfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgTkEsIG9ic2V4cF9BNDg1L29ic2V4cF9ETVNPKSkKICAKICBmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwXyIsIHJlcywgImtiLnRzdiIpKSwgc2VwID0gIlx0IikKfQoKCmBgYAoKIyMjIyMgQXN5bmMKYGBge3J9Cmxvb3BzIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfc2NvcmUudHN2IikpCgpyZXMgPC0gMjUKCmZvciAocmVzIGluIGMoMjUsIDEwLCA1KSl7CiAgCiAgdGVtcC5VVCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfQXN5bmMuVVRfIiwgcmVzLCAia2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChpZCwgb2JzZXJ2ZWQsICJPL0UiKQogIGNvbG5hbWVzKHRlbXAuVVQpIDwtIGMoImlkIiwgIm9ic19VVCIsICJvYnNleHBfVVQiKQogIAogIHRlbXAuQUlEIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9Bc3luYy5BSURfIiwgcmVzLCAia2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IGVuZDEgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoY2hyb20xLCBiaW5TaXplLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcHMkaWQpICU+JQogICAgZHBseXI6OnNlbGVjdChpZCwgb2JzZXJ2ZWQsICJPL0UiKQogIGNvbG5hbWVzKHRlbXAuQUlEKSA8LSBjKCJpZCIsICJvYnNfQUlEIiwgIm9ic2V4cF9BSUQiKQoKICAKICB0ZW1wIDwtIGZ1bGxfam9pbih0ZW1wLlVULCB0ZW1wLkFJRCwgYnkgPSBjKCJpZCIpKSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKG9lRkNfQUlEX1VUID0gaWZfZWxzZShvYnNleHBfVVQgPT0gMCwgTkEsIG9ic2V4cF9BSUQvb2JzZXhwX1VUKSkKICAKICBmd3JpdGUodGVtcCwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwXyIsIHJlcywgImtiX2FzeW5jLnRzdiIpKSwgc2VwID0gIlx0IikKfQoKCmBgYAoKIyMjIyBDb21wYXJpbmcgb2JzL2V4cCBmcm9tIGNocm9tbW9zaWdodCBsb29wIHNjb3JlcwojIyMjIyBkVEFHIHBlciByZXMKYGBge3J9CiMgSW1wb3J0aW5nIGxvb3BzCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQoKZm9yKHJlcyBpbiBjKDI1LCAxMCwgNSkpewogIG1pblZhbHVlIDwtIC00CiAgbWF4VmFsdWUgPC0gNQogIG9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHBfIiwgcmVzLCAia2IudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKICAKICAKICAjIGRUQUcKICBvYnNleHAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShvYnNleHAkbG9nX29ic2V4cF9ETVNPLCBvYnNleHAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQogIG9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzEgPC0gZ2dwbG90KG9ic2V4cCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgICBnZ3RpdGxlKHBhc3RlMChyZXMsICJrYiwgbG9nMihvYnMvZXhwKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKICAKICAKICAjIFZpc3VhbGl6ZSBVUCBET1dOIGxvb3BzCiAgdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfZFRBRywgbiA9IDEwMCkKICB0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogICAgZ2d0aXRsZShwYXN0ZTAocmVzLCAia2IsIGxvZzIob2JzL2V4cCksIGRvd24iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkKICAKICAKICB0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Aubm8kaWQpCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfZFRBRywgbiA9IDEwMCkKICB0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzMgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogICAgZ2d0aXRsZShwYXN0ZTAocmVzLCAia2IsIGxvZzIob2JzL2V4cCksIG5vIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpCiAgCiAgdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLnVwJGlkKQogIHRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCiAgdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQogIGc0IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICAgIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICAgIGdndGl0bGUocGFzdGUwKHJlcywgImtiLCBsb2cyKG9icy9leHApLCB1cCIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKQogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX2RUQUdfdnNfRE1TT18iLCByZXMsICJrYiIpCiAgaGVpZ2h0IDwtIDQKICB3aWR0aCA8LSAxMgogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCiAgZGV2Lm9mZigpCn0KCmBgYAoKIyMjIyMgZFRBRyBhbGwgcmVzCmBgYHtyfQojIEltcG9ydGluZyBsb29wcwpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKCm1pblZhbHVlIDwtIC00Cm1heFZhbHVlIDwtIDUKCm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZFRBRyA9IGlmX2Vsc2Uob2JzZXhwX2RUQUcgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX2RUQUcpKSwKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCgoKIyBkVEFHCm9ic2V4cCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KG9ic2V4cCRsb2dfb2JzZXhwX0RNU08sIG9ic2V4cCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCm9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcxIDwtIGdncGxvdChvYnNleHAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCkiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgojIFZpc3VhbGl6ZSBVUCBET1dOIGxvb3BzCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5kb3duJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcyIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBkb3duIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5ubyRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfZFRBRywgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnMyA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSwgbm8iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AudXAkaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzQgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIHVwIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKCmZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX2RUQUdfdnNfRE1TTyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDEyCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzEsIGc0LCBnMywgZzIsIG5jb2wgPSA0KSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKCgojIFN0cnVjdHVyYWwKbG9vcC5zdHIgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3N0cnVjdHVyZS5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLnN0ciRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfZFRBRywgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnNSA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSwgc3RydWN0dXJhbCBsb29wcyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgUmVnIChQRS1QRSkKbG9vcC5yZWcgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AucmVnJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc2IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCByZWd1bGF0b3J5IGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfZFRBR192c19ETVNPX3N0cl92c19yZWciKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA2CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQpgYGAKIyMjIyMjIFBsb3R0aW5nIG9ubHkgc3Vic2V0CmBgYHtyfQoKc3BlY2lmaWNMb29wLjI1a2IgPC0gZnJlYWQoaGVyZShsb29wRGlyLCAiRzEuRE1TTy5NZXJnZWRfY2hyb21vc2lnaHRfMjVrYi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpzcGVjaWZpY0xvb3AuMTBrYiA8LSBmcmVhZChoZXJlKGxvb3BEaXIsICJHMS5ETVNPLk1lcmdlZF9jaHJvbW9zaWdodF8xMGtiLmJlZHBlIikpICU+JQogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnNwZWNpZmljTG9vcC41a2IgPC0gZnJlYWQoaGVyZShsb29wRGlyLCAiRzEuRE1TTy5NZXJnZWRfY2hyb21vc2lnaHRfNWtiLmJlZHBlIikpICU+JQogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCgpzcGVjaWZpY0xvb3BzLkRNU08gPC0gYyhzcGVjaWZpY0xvb3AuMjVrYiRpZCwgc3BlY2lmaWNMb29wLjEwa2IkaWQsIHNwZWNpZmljTG9vcC41a2IkaWQpCgoKbWluVmFsdWUgPC0gLTQKbWF4VmFsdWUgPC0gNQoKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpKQoKCgoKIyBTdHJ1Y3R1cmFsCmxvb3Auc3RyIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5zdHIkaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkICVpbiUgc3BlY2lmaWNMb29wcy5ETVNPKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc1IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkICVpbiUgc3BlY2lmaWNMb29wcy5ETVNPKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc2IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCByZWd1bGF0b3J5IGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfZFRBR192c19ETVNPX3N0cl92c19yZWdfRE1TT3NwZWNpZmljTG9vcHMiKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA2CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQoKYGBgCiMjIyMjIyBQbG90dGluZyAxbWIKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKCiMgSW1wb3J0IG9icy9leHAgc2NvcmVzIGFuZCBtZXJnZSB0byB0aGUgZGF0YXNldAptaW5WYWx1ZSA8LSAtNAptYXhWYWx1ZSA8LSA1Cm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCiMgTWVyZ2UgZGF0YXNldApkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKQoKCiMgSW1wb3J0aW5nIGxvb3BzCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQoKIyBkaXN0YW5jZSBmaWx0ZXIKb2JzZXhwIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZGlzdGFuY2UgPiAxZTYpCgoKIyBkVEFHCm9ic2V4cCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KG9ic2V4cCRsb2dfb2JzZXhwX0RNU08sIG9ic2V4cCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCm9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcxIDwtIGdncGxvdChvYnNleHAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCkiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgojIFZpc3VhbGl6ZSBVUCBET1dOIGxvb3BzCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5kb3duJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcyIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBkb3duIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5ubyRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfZFRBRywgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnMyA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSwgbm8iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AudXAkaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzQgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIHVwIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKCmZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX2RUQUdfdnNfRE1TT18xbWJvdmVyIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gMTIKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCmRldi5vZmYoKQoKCiMgU3RydWN0dXJhbApsb29wLnN0ciA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Auc3RyJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc1IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzYgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIHJlZ3VsYXRvcnkgbG9vcHMiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgpmaWxlTmFtZSA8LSBwYXN0ZTAoIm9ic2V4cF9kVEFHX3ZzX0RNU09fMW1ib3Zlcl9zdHJfdnNfcmVnIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gNgpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGc1LCBnNiwgbmNvbCA9IDIpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGc1LCBnNiwgbmNvbCA9IDIpKQpkZXYub2ZmKCkKYGBgCgojIyMjIyMgUGxvdHRpbmcgT2JzCmBgYHtyfQptaW5WYWx1ZSA8LSAtNAptYXhWYWx1ZSA8LSAxMApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNfRE1TTyA9IGlmX2Vsc2Uob2JzX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic19kVEFHID0gaWZfZWxzZShvYnNfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzX0E0ODUgPSBpZl9lbHNlKG9ic19BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic19BNDg1KSkpCgojIEltcG9ydGluZyBsb29wcwpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKCgoKIyBkVEFHCm9ic2V4cCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KG9ic2V4cCRsb2dfb2JzX0RNU08sIG9ic2V4cCRsb2dfb2JzX2RUQUcsIG4gPSAxMDApCm9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcxIDwtIGdncGxvdChvYnNleHAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgVmlzdWFsaXplIFVQIERPV04gbG9vcHMKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgZG93biIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Aubm8kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzMgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgbm8iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AudXAkaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzQgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgdXAiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfZFRBR192c19ETVNPX29icyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDEyCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzEsIGc0LCBnMywgZzIsIG5jb2wgPSA0KSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKCgojIFN0cnVjdHVyYWwKbG9vcC5zdHIgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3N0cnVjdHVyZS5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLnN0ciRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic19ETVNPLCB0ZW1wJGxvZ19vYnNfZFRBRywgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnNSA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzX0RNU08sIHkgPSBsb2dfb2JzX2RUQUcsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMpLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX2RUQUcsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzYgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19kVEFHLCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgcmVndWxhdG9yeSBsb29wcyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCmZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX2RUQUdfdnNfRE1TT19vYnNfc3RyX3ZzX3JlZyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDYKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCmBgYAoKIyMjIyMgQXN5bmMuQUlEIGFsbCByZXMKYGBge3J9CiMgSW1wb3J0aW5nIGxvb3BzCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQoKbWluVmFsdWUgPC0gLTgKbWF4VmFsdWUgPC0gNwoKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cF9Bc3luYy50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9VVCA9IGlmX2Vsc2Uob2JzZXhwX1VUID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9VVCkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BSUQgPSBpZl9lbHNlKG9ic2V4cF9BSUQgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0FJRCkpKQoKCgojIGRUQUcKb2JzZXhwJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkob2JzZXhwJGxvZ19vYnNleHBfVVQsIG9ic2V4cCRsb2dfb2JzZXhwX0FJRCwgbiA9IDEwMCkKb2JzZXhwIDwtIG9ic2V4cCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzEgPC0gZ2dwbG90KG9ic2V4cCwgYWVzKHggPSBsb2dfb2JzZXhwX1VULCB5ID0gbG9nX29ic2V4cF9BSUQsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgVmlzdWFsaXplIFVQIERPV04gbG9vcHMKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfVVQsIHRlbXAkbG9nX29ic2V4cF9BSUQsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9VVCwgeSA9IGxvZ19vYnNleHBfQUlELCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIGRvd24iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLm5vJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX1VULCB0ZW1wJGxvZ19vYnNleHBfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmczIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfVVQsIHkgPSBsb2dfb2JzZXhwX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBubyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC51cCRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9VVCwgdGVtcCRsb2dfb2JzZXhwX0FJRCwgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnNCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzZXhwX1VULCB5ID0gbG9nX29ic2V4cF9BSUQsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSwgdXAiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfQUlEX3ZzX1VUIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gMTIKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCmRldi5vZmYoKQoKCiMgU3RydWN0dXJhbApsb29wLnN0ciA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Auc3RyJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX1VULCB0ZW1wJGxvZ19vYnNleHBfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc1IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfVVQsIHkgPSBsb2dfb2JzZXhwX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfVVQsIHRlbXAkbG9nX29ic2V4cF9BSUQsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzYgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9VVCwgeSA9IGxvZ19vYnNleHBfQUlELCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIHJlZ3VsYXRvcnkgbG9vcHMiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgpmaWxlTmFtZSA8LSBwYXN0ZTAoIm9ic2V4cF9BSURfdnNfVVRfc3RyX3ZzX3JlZyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDYKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCmBgYAoKIyMjIyMjIFBsb3R0aW5nIE9icwpgYGB7cn0KCm1pblZhbHVlIDwtIC0yMAptYXhWYWx1ZSA8LSAxMAoKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cF9Bc3luYy50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9VVCA9IGlmX2Vsc2Uob2JzZXhwX1VUID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9VVCkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BSUQgPSBpZl9lbHNlKG9ic2V4cF9BSUQgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0FJRCkpLAogICAgICAgICAgICAgICAgbG9nX29ic19VVCA9IGlmX2Vsc2Uob2JzX1VUID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic19VVCkpLAogICAgICAgICAgICAgICAgbG9nX29ic19BSUQgPSBpZl9lbHNlKG9ic19BSUQgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzX0FJRCkpKQoKIyBJbXBvcnRpbmcgbG9vcHMKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCgoKCiMgZFRBRwpvYnNleHAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShvYnNleHAkbG9nX29ic19VVCwgb2JzZXhwJGxvZ19vYnNfQUlELCBuID0gMTAwKQpvYnNleHAgPC0gb2JzZXhwICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnMSA8LSBnZ3Bsb3Qob2JzZXhwLCBhZXMoeCA9IGxvZ19vYnNfVVQsIHkgPSBsb2dfb2JzX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icykiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgojIFZpc3VhbGl6ZSBVUCBET1dOIGxvb3BzCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5kb3duJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzX1VULCB0ZW1wJGxvZ19vYnNfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcyIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNfVVQsIHkgPSBsb2dfb2JzX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icyksIGRvd24iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLm5vJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzX1VULCB0ZW1wJGxvZ19vYnNfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmczIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNfVVQsIHkgPSBsb2dfb2JzX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icyksIG5vIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLnVwJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzX1VULCB0ZW1wJGxvZ19vYnNfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc0IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNfVVQsIHkgPSBsb2dfb2JzX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icyksIHVwIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKCmZpbGVOYW1lIDwtIHBhc3RlMCgib2JzX0FJRF92c19VVF9vYnMiKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSAxMgpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzEsIGc0LCBnMywgZzIsIG5jb2wgPSA0KSkKZGV2Lm9mZigpCgoKIyBTdHJ1Y3R1cmFsCmxvb3Auc3RyIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5zdHIkaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfVVQsIHRlbXAkbG9nX29ic19BSUQsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzUgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19VVCwgeSA9IGxvZ19vYnNfQUlELCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgc3RydWN0dXJhbCBsb29wcyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgUmVnIChQRS1QRSkKbG9vcC5yZWcgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AucmVnJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzX1VULCB0ZW1wJGxvZ19vYnNfQUlELCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc2IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNfVVQsIHkgPSBsb2dfb2JzX0FJRCwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icyksIHJlZ3VsYXRvcnkgbG9vcHMiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgpmaWxlTmFtZSA8LSBwYXN0ZTAoIm9ic19BSURfdnNfVVRfb2JzX3N0cl92c19yZWciKQpoZWlnaHQgPC0gNAp3aWR0aCA8LSA2CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzUsIGc2LCBuY29sID0gMikpCmRldi5vZmYoKQpgYGAKCiMjIyMjIEE0ODUgcGVyIHJlcwpgYGB7cn0KIyBJbXBvcnRpbmcgbG9vcHMKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfQTQ4NXZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9BNDg1dnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCgpmb3IocmVzIGluIGMoMjUsIDEwLCA1KSl7CiAgbWluVmFsdWUgPC0gLTQKICBtYXhWYWx1ZSA8LSA1CiAgb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cF8iLCByZXMsICJrYi50c3YiKSkpICU+JQogICAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKICAKICAKICAjIEE0ODUKICBvYnNleHAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eShvYnNleHAkbG9nX29ic2V4cF9ETVNPLCBvYnNleHAkbG9nX29ic2V4cF9BNDg1LCBuID0gMTAwKQogIG9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzEgPC0gZ2dwbG90KG9ic2V4cCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX0E0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgICBnZ3RpdGxlKHBhc3RlMChyZXMsICJrYiwgbG9nMihvYnMvZXhwKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKICAKICAKICAjIFZpc3VhbGl6ZSBVUCBET1dOIGxvb3BzCiAgdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfQTQ4NSwgbiA9IDEwMCkKICB0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogICAgZ2d0aXRsZShwYXN0ZTAocmVzLCAia2IsIGxvZzIob2JzL2V4cCksIGRvd24iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCiAgCiAgCiAgdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLm5vJGlkKQogIHRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX0E0ODUsIG4gPSAxMDApCiAgdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQogIGczIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICAgIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICAgIGdndGl0bGUocGFzdGUwKHJlcywgImtiLCBsb2cyKG9icy9leHApLCBubyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKICAKICB0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AudXAkaWQpCiAgdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfQTQ4NSwgbiA9IDEwMCkKICB0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCiAgZzQgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogICAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogICAgZ2d0aXRsZShwYXN0ZTAocmVzLCAia2IsIGxvZzIob2JzL2V4cCksIHVwIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAogIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX0E0ODVfdnNfRE1TT18iLCByZXMsICJrYiIpCiAgaGVpZ2h0IDwtIDQKICB3aWR0aCA8LSAxMgogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCiAgZGV2Lm9mZigpCn0KCmBgYAojIyMjIyBBNDg1IGFsbCByZXMKYGBge3J9CiMgSW1wb3J0aW5nIGxvb3BzCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9BNDg1dnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfQTQ4NXZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQoKbWluVmFsdWUgPC0gLTQKbWF4VmFsdWUgPC0gNQoKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogICAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCgojIEE0ODUKb2JzZXhwJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkob2JzZXhwJGxvZ19vYnNleHBfRE1TTywgb2JzZXhwJGxvZ19vYnNleHBfQTQ4NSwgbiA9IDEwMCkKb2JzZXhwIDwtIG9ic2V4cCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzEgPC0gZ2dwbG90KG9ic2V4cCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX0E0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgVmlzdWFsaXplIFVQIERPV04gbG9vcHMKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIGRvd24iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLm5vJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9BNDg1LCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmczIDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBubyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC51cCRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic2V4cF9ETVNPLCB0ZW1wJGxvZ19vYnNleHBfQTQ4NSwgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnNCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzZXhwX0RNU08sIHkgPSBsb2dfb2JzZXhwX0E0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMvZXhwKSwgdXAiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfQTQ4NV92c19ETVNPIikKaGVpZ2h0IDwtIDQKd2lkdGggPC0gMTIKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKGcxLCBnNCwgZzMsIGcyLCBuY29sID0gNCkpCmRldi5vZmYoKQoKCiMgU3RydWN0dXJhbApsb29wLnN0ciA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Auc3RyJGlkKQp0ZW1wJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkodGVtcCRsb2dfb2JzZXhwX0RNU08sIHRlbXAkbG9nX29ic2V4cF9BNDg1LCBuID0gMTAwKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmc1IDwtIGdncGxvdCh0ZW1wLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKyAKICBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfdmlyaWRpcyhndWlkZSA9ICJub25lIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwogIGdndGl0bGUocGFzdGUwKCJsb2cyKG9icy9leHApLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNleHBfRE1TTywgdGVtcCRsb2dfb2JzZXhwX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzYgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic2V4cF9ETVNPLCB5ID0gbG9nX29ic2V4cF9BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzL2V4cCksIHJlZ3VsYXRvcnkgbG9vcHMiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgpmaWxlTmFtZSA8LSBwYXN0ZTAoIm9ic2V4cF9BNDg1X3ZzX0RNU09fc3RyX3ZzX3JlZyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDYKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCmBgYAojIyMjIyMgUGxvdHRpbmcgT2JzCmBgYHtyfQptaW5WYWx1ZSA8LSAtNAptYXhWYWx1ZSA8LSAxMApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNfRE1TTyA9IGlmX2Vsc2Uob2JzX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic19kVEFHID0gaWZfZWxzZShvYnNfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzX0E0ODUgPSBpZl9lbHNlKG9ic19BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic19BNDg1KSkpCgojIEltcG9ydGluZyBsb29wcwpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfQTQ4NXZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGJpblNpemUgPSBWMyAtIFYyLAogICAgICAgICAgICAgICAgaWQgPSBwYXN0ZShWMSwgYmluU2l6ZSwgVjIsIFY1LCBzZXAgPSAiXyIpKQpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9BNDg1dnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfYWxsX0E0ODV2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKCgoKIyBkVEFHCm9ic2V4cCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KG9ic2V4cCRsb2dfb2JzX0RNU08sIG9ic2V4cCRsb2dfb2JzX0E0ODUsIG4gPSAxMDApCm9ic2V4cCA8LSBvYnNleHAgJT4lIGRwbHlyOjphcnJhbmdlKGRlbnNpdHkpCmcxIDwtIGdncGxvdChvYnNleHAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCiMgVmlzdWFsaXplIFVQIERPV04gbG9vcHMKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLmRvd24kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzIgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgZG93biIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3Aubm8kaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzMgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgbm8iKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgp0ZW1wIDwtIG9ic2V4cCAlPiUgZHBseXI6OmZpbHRlcihpZCAlaW4lIGxvb3AudXAkaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzQgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgdXAiKSkgKwogICAgY29vcmRfZml4ZWQoeGxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSwgeWxpbSA9IGMobWluVmFsdWUsIG1heFZhbHVlKSkgCgoKZmlsZU5hbWUgPC0gcGFzdGUwKCJvYnNleHBfQTQ4NV92c19ETVNPX29icyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDEyCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQoZzEsIGc0LCBnMywgZzIsIG5jb2wgPSA0KSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnMSwgZzQsIGczLCBnMiwgbmNvbCA9IDQpKQpkZXYub2ZmKCkKCgojIFN0cnVjdHVyYWwKbG9vcC5zdHIgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3N0cnVjdHVyZS5iZWRwZSIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShiaW5TaXplID0gVjMgLSBWMiwKICAgICAgICAgICAgICAgIGlkID0gcGFzdGUoVjEsIGJpblNpemUsIFYyLCBWNSwgc2VwID0gIl8iKSkKdGVtcCA8LSBvYnNleHAgJT4lIGRwbHlyOjpmaWx0ZXIoaWQgJWluJSBsb29wLnN0ciRpZCkKdGVtcCRkZW5zaXR5IDwtIGdldF9kZW5zaXR5KHRlbXAkbG9nX29ic19ETVNPLCB0ZW1wJGxvZ19vYnNfQTQ4NSwgbiA9IDEwMCkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6YXJyYW5nZShkZW5zaXR5KQpnNSA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBsb2dfb2JzX0RNU08sIHkgPSBsb2dfb2JzX0E0ODUsIGNvbG9yID0gZGVuc2l0eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZ3VpZGUgPSAibm9uZSIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZ3RpdGxlKHBhc3RlMCgibG9nMihvYnMpLCBzdHJ1Y3R1cmFsIGxvb3BzIikpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpIAoKIyBSZWcgKFBFLVBFKQpsb29wLnJlZyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGUuYmVkcGUiKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoYmluU2l6ZSA9IFYzIC0gVjIsCiAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBiaW5TaXplLCBWMiwgVjUsIHNlcCA9ICJfIikpCnRlbXAgPC0gb2JzZXhwICU+JSBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgbG9vcC5yZWckaWQpCnRlbXAkZGVuc2l0eSA8LSBnZXRfZGVuc2l0eSh0ZW1wJGxvZ19vYnNfRE1TTywgdGVtcCRsb2dfb2JzX0E0ODUsIG4gPSAxMDApCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKZzYgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gbG9nX29ic19ETVNPLCB5ID0gbG9nX29ic19BNDg1LCBjb2xvciA9IGRlbnNpdHkpKSArIAogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl92aXJpZGlzKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2d0aXRsZShwYXN0ZTAoImxvZzIob2JzKSwgcmVndWxhdG9yeSBsb29wcyIpKSArCiAgICBjb29yZF9maXhlZCh4bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpLCB5bGltID0gYyhtaW5WYWx1ZSwgbWF4VmFsdWUpKSAKCmZpbGVOYW1lIDwtIHBhc3RlMCgib2JzZXhwX0E0ODVfdnNfRE1TT19vYnNfc3RyX3ZzX3JlZyIpCmhlaWdodCA8LSA0CndpZHRoIDwtIDYKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChnNSwgZzYsIG5jb2wgPSAyKSkKZGV2Lm9mZigpCmBgYAoKIyMjIFsyLjI2XSBSZXBlYXRpbmcgZmV3IGFuYWx5c2lzIHdpdGggb2JzL2V4cAojIyMjIEZ1bmN0aW9uCmBgYHtyfQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnRfb2UgPC0gZnVuY3Rpb24oZGF0YSwgZmlnRGlyLCBuYW1lLCBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IEZBTFNFKXsKICBhdmdfc2NvcmVzX2xvbmcgPC0gZGF0YSAlPiUKICAgIGdyb3VwX2J5KGRpc3RhbmNlLCBBbm5vMikgJT4lCiAgICBzdW1tYXJpc2UoYXZnX3Njb3JlID0gbWVhbihzY29yZSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICB1bmdyb3VwKCkgCiAgYXZnX3Njb3Jlc19sb25nJEFubm8yIDwtIGZhY3Rvcihhdmdfc2NvcmVzX2xvbmckQW5ubzIsIGxldmVsID0gbG9vcExpc3QpCiAgcDQgPC0gZ2dwbG90KGF2Z19zY29yZXNfbG9uZywgYWVzKHggPSBkaXN0YW5jZSwgeSA9IGF2Z19zY29yZSwgY29sb3IgPSBBbm5vMiwgZmlsbCA9IEFubm8yKSkgKyAKICAgIGdlb21fc21vb3RoKHNob3cubGVnZW5kID0gVFJVRSwgc2UgPSBzZSkgICsKICAgICN5bGltKDAsIDAuNSkgKwogICAgdGhlbWVfY2xhc3NpYygpICsgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JMaXN0KSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG5hbWUpLAogICAgICAgICB4ID0gIkRpc3RhbmNlIiwKICAgICAgICAgeSA9ICJBdmVyYWdlIFNjb3JlIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiAgCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJkaXN0X3ZzX3Njb3JlX2xpbmVQbG90XyIsIG5hbWUpCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCAKICAgICAgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMykKICBwcmludChwNCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICAgIHdpZHRoID0gNCwgaGVpZ2h0ID0gMykKICBwcmludChwNCkKICBkZXYub2ZmKCkKfSAKCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnRfb2UgPC0gZnVuY3Rpb24oZGF0YSwgZmlnRGlyLCBuYW1lLCBsb29wTGlzdCwgY29sb3JMaXN0LCBzZSA9IEZBTFNFKXsKICBhdmdfc2NvcmVzX2xvbmcgPC0gZGF0YSAlPiUKICAgIGdyb3VwX2J5KGRpc3RhbmNlLCBBbm5vMikgJT4lCiAgICBzdW1tYXJpc2UoYXZnX3Njb3JlID0gbWVhbihzY29yZSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICB1bmdyb3VwKCkgCiAgYXZnX3Njb3Jlc19sb25nJEFubm8yIDwtIGZhY3Rvcihhdmdfc2NvcmVzX2xvbmckQW5ubzIsIGxldmVsID0gbG9vcExpc3QpCiAgcDQgPC0gZ2dwbG90KGF2Z19zY29yZXNfbG9uZywgYWVzKHggPSBkaXN0YW5jZSwgeSA9IGF2Z19zY29yZSwgY29sb3IgPSBBbm5vMiwgZmlsbCA9IEFubm8yKSkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgIGdlb21fc21vb3RoKHNob3cubGVnZW5kID0gVFJVRSwgc2UgPSBzZSkgICsKICAgIHRoZW1lX2NsYXNzaWMoKSArICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvckxpc3QpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlMChuYW1lKSwKICAgICAgICAgeCA9ICJEaXN0YW5jZSIsCiAgICAgICAgIHkgPSAiQXZlcmFnZSBEaWZmIFNjb3JlIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpIAogIAogIGZpbGVOYW1lIDwtIHBhc3RlMCgiZGlzdF92c19zY29yZV9kaWZmbGluZVBsb3RfIiwgbmFtZSkKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIAogICAgICByZXMgPSA2MDAsIHVuaXRzID0gImluIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksIAogICAgICAgICAgd2lkdGggPSA0LCBoZWlnaHQgPSAzKQogIHByaW50KHA0KQogIGRldi5vZmYoKQp9IAoKY3JlYXRlX2Rpc3RfYmFycGxvdF9vZSA8LSBmdW5jdGlvbihkYXRhLCBmaWdEaXIsIG5hbWUsIG5vdGUsIGxvb3BMaXN0LCBkaWZmQ3V0b2ZmLCBkaXN0YW5jZUZpbHRlciA9IDIqZTYpewogICAgZGF0YSA8LSBkYXRhICU+JSAKICAgIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgIHVwZG93bl9kVEFHX0RNU08gPSBpZmVsc2UobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA+IGRpZmZDdXRvZmYsICJVUCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpLAogICAgICAgICAgICAgICAgICB1cGRvd25fQTQ4NV9ETVNPID0gaWZlbHNlKGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA+IC1kaWZmQ3V0b2ZmLCAiTk8iLCAiRE9XTiIpKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgbG9vcExpc3QsCiAgICAgICAgICAgICAgICAgIGRpc3RhbmNlIDwgZGlzdGFuY2VGaWx0ZXIpCiAgZGF0YSR1cGRvd25fZFRBR19ETVNPIDwtIGZhY3RvcihkYXRhJHVwZG93bl9kVEFHX0RNU08sIGxldmVscyA9IGMoIlVQIiwgIk5PIiwgIkRPV04iKSkKICBkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIAogIAogIHRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChBbm5vMiwgZGlzdGFuY2UsIHVwZG93bl9kVEFHX0RNU08sIHVwZG93bl9BNDg1X0RNU08pICU+JQogICAgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGxvb3BMaXN0LAogICAgICAgICAgICAgICAgICB1cGRvd25fZFRBR19ETVNPICVpbiUgYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIHAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gdXBkb3duX2RUQUdfRE1TTywgeSA9IGRpc3RhbmNlKSkgKwogICAgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSB1cGRvd25fZFRBR19ETVNPKSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gdXBkb3duX2RUQUdfRE1TTyksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUobm90ZSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKQogIGZpbGVOYW1lIDwtIHBhc3RlMCgic2l6ZV9iYXJwbG90XyIsIG5hbWUsICJfZFRBR192c19ETVNPXyIsIG5vdGUsICJfIiwgZGlmZkN1dG9mZikKICBoZWlnaHQgPC0gMwogIHdpZHRoIDwtIDQKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQogIHN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICAKICAKICB0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoQW5ubzIsIGRpc3RhbmNlLCB1cGRvd25fZFRBR19ETVNPLCB1cGRvd25fQTQ4NV9ETVNPKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBsb29wTGlzdCwKICAgICAgICAgICAgICAgICAgdXBkb3duX0E0ODVfRE1TTyAlaW4lIGMoIlVQIiwgIk5PIiwgICJET1dOIikpCiAgcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSB1cGRvd25fQTQ4NV9ETVNPLCB5ID0gZGlzdGFuY2UpKSArCiAgICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHVwZG93bl9BNDg1X0RNU08pKSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSB1cGRvd25fQTQ4NV9ETVNPKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShub3RlKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfa2JfbWIpCiAgZmlsZU5hbWUgPC0gcGFzdGUwKCJzaXplX2JhcnBsb3RfIiwgbmFtZSwgIl9BNDg1X3ZzX0RNU09fIiwgbm90ZSwgIl8iLCBkaWZmQ3V0b2ZmKQogIGhlaWdodCA8LSAzCiAgd2lkdGggPC0gNAogIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCiAgc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKICBwcmludChwKQogIGRldi5vZmYoKQp9CgpjcmVhdGVfbG9vcF9zY2F0dGVycGxvdF9vZSA8LSBmdW5jdGlvbihkYXRhLCBmaWdEaXIsIG5hbWUsIEFubm8yTGlzdCwgZGlmZkN1dG9mZil7CiAgZGF0YSA8LSBkYXRhICU+JQogICAgZHBseXI6Om11dGF0ZSh1cGRvd25fZFRBR19ETVNPID0gaWZlbHNlKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPiBkaWZmQ3V0b2ZmLCAiVVAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA+IC1kaWZmQ3V0b2ZmLCAiTk8iLCAiRE9XTiIpKSwKICAgICAgICAgICAgICAgICAgdXBkb3duX0E0ODVfRE1TTyA9IGlmZWxzZShsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSkpICU+JQogICAgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIEFubm8yTGlzdCkKICBkYXRhJHVwZG93bl9kVEFHX0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX2RUQUdfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIGRhdGEkdXBkb3duX0E0ODVfRE1TTyA8LSBmYWN0b3IoZGF0YSR1cGRvd25fQTQ4NV9ETVNPLCBsZXZlbHMgPSBjKCJVUCIsICJOTyIsICJET1dOIikpCiAgCiAgbnVtLnVwIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJVUCJdCiAgbnVtLm5vIDwtIChzdW1tYXJ5KGRhdGEkdXBkb3duX2RUQUdfRE1TTykpWyJOTyJdCiAgbnVtLmRvd24gPC0gKHN1bW1hcnkoZGF0YSR1cGRvd25fZFRBR19ETVNPKSlbIkRPV04iXQogIG51bS5hbGwgPC0gbnVtLnVwICsgbnVtLm5vICsgbnVtLmRvd24KICBwZXJjLnVwIDwtIHJvdW5kKG51bS51cCAvIG51bS5hbGwgKiAxMDAsIDIpCiAgcGVyYy5ubyA8LSByb3VuZChudW0ubm8gLyBudW0uYWxsICogMTAwLCAyKQogIHBlcmMuZG93biA8LSByb3VuZChudW0uZG93biAvIG51bS5hbGwgKiAxMDAsIDIpCiAgCiAgIyMjIFNjYXR0ZXJwbG90CiAgICBtaW5WYWx1ZSA8LSAtNAogIG1heFZhbHVlIDwtIDUKICBkYXRhJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoZGF0YSRsb2dfb2JzZXhwX0RNU08sIGRhdGEkbG9nX29ic2V4cF9kVEFHLCBuID0gMTAwKQogIGRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKICBjb3JyZWxhdGlvbiA8LSBjb3IoZGF0YSRsb2dfb2JzZXhwX0RNU08sIGRhdGEkbG9nX29ic2V4cF9kVEFHKQogIHAxIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfZFRBRywgY29sb3IgPSBkZW5zaXR5KSkgKwogICAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLCBsYWJlbCA9IHBhc3RlMCgiVVA6ICIsIG51bS51cCwgIiAoIiwgcGVyYy51cCwgIiUpIiksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLTEsIGxhYmVsID0gcGFzdGUwKCJOTzogIiwgbnVtLm5vLCAiICgiLCBwZXJjLm5vLCAiJSkiKSwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1pblZhbHVlLCB5ID0gbWF4VmFsdWUtMiwgbGFiZWwgPSBwYXN0ZTAoIkRPV046ICIsIG51bS5kb3duLCAiICgiLCBwZXJjLmRvd24sICIlKSIpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogICAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShuYW1lKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKICAKICAKICBudW0udXAgPC0gKHN1bW1hcnkoZGF0YSR1cGRvd25fQTQ4NV9ETVNPKSlbIlVQIl0KICBudW0ubm8gPC0gKHN1bW1hcnkoZGF0YSR1cGRvd25fQTQ4NV9ETVNPKSlbIk5PIl0KICBudW0uZG93biA8LSAoc3VtbWFyeShkYXRhJHVwZG93bl9BNDg1X0RNU08pKVsiRE9XTiJdCiAgbnVtLmFsbCA8LSBudW0udXAgKyBudW0ubm8gKyBudW0uZG93bgogIHBlcmMudXAgPC0gcm91bmQobnVtLnVwIC8gbnVtLmFsbCAqIDEwMCwgMikKICBwZXJjLm5vIDwtIHJvdW5kKG51bS5ubyAvIG51bS5hbGwgKiAxMDAsIDIpCiAgcGVyYy5kb3duIDwtIHJvdW5kKG51bS5kb3duIC8gbnVtLmFsbCAqIDEwMCwgMikKICAKICBkYXRhJGRlbnNpdHkgPC0gZ2V0X2RlbnNpdHkoZGF0YSRsb2dfb2JzZXhwX0RNU08sIGRhdGEkbG9nX29ic2V4cF9BNDg1LCBuID0gMTAwKQogIGRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmFycmFuZ2UoZGVuc2l0eSkKICBjb3JyZWxhdGlvbiA8LSBjb3IoZGF0YSRsb2dfb2JzZXhwX0RNU08sIGRhdGEkbG9nX29ic2V4cF9BNDg1KQogIHAyIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGxvZ19vYnNleHBfRE1TTywgeSA9IGxvZ19vYnNleHBfQTQ4NSwgY29sb3IgPSBkZW5zaXR5KSkgKwogICAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogICAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSksIHlsaW0gPSBjKG1pblZhbHVlLCBtYXhWYWx1ZSkpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gLWRpZmZDdXRvZmYsIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSBkaWZmQ3V0b2ZmLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gImRvdHRlZCIpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBjb2xvciA9ICJncmV5IikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAwLjUsIGNvbG9yID0gImdyZXkiKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLCBsYWJlbCA9IHBhc3RlMCgiVVA6ICIsIG51bS51cCwgIiAoIiwgcGVyYy51cCwgIiUpIiksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBoanVzdCA9IDAsIHNpemUgPSAzKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLTEsIGxhYmVsID0gcGFzdGUwKCJOTzogIiwgbnVtLm5vLCAiICgiLCBwZXJjLm5vLCAiJSkiKSwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1pblZhbHVlLCB5ID0gbWF4VmFsdWUtMiwgbGFiZWwgPSBwYXN0ZTAoIkRPV046ICIsIG51bS5kb3duLCAiICgiLCBwZXJjLmRvd24sICIlKSIpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykgKwogICAgdGhlbWVfY2xhc3NpYygpICsgZ2d0aXRsZShuYW1lKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSBtaW5WYWx1ZSwgeSA9IG1heFZhbHVlLCBsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpLCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKQoKICAKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoInNjYXR0ZXJwbG90XyIsIG5hbWUsICJfIiwgZGlmZkN1dG9mZikKICBwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iLCB3aWR0aCA9IDUqMS41LCBoZWlnaHQgPSAyLjUqMS41KQogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIGFsaWduID0gImgiKSkKICBkZXYub2ZmKCkKICAKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICAgIHdpZHRoID0gNSoxLjUsIGhlaWdodCA9IDIuNSoxLjUpCiAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgYWxpZ24gPSAiaCIpKQogIGRldi5vZmYoKQp9CgptYWtlX2RpZmZfYmVkcGVfb2UgPC0gZnVuY3Rpb24oZGF0YSwgbmFtZSwgQW5ubzJMaXN0LCBvdXREaXIsIGRpZmZDdXRvZmYpewogIGRhdGEgPC0gZGF0YSAlPiUKICAgIGRwbHlyOjptdXRhdGUodXBkb3duX2RUQUdfRE1TTyA9IGlmZWxzZShsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID4gZGlmZkN1dG9mZiwgIlVQIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPiAtZGlmZkN1dG9mZiwgIk5PIiwgIkRPV04iKSksCiAgICAgICAgICAgICAgICAgIHVwZG93bl9BNDg1X0RNU08gPSBpZmVsc2UobG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA+IGRpZmZDdXRvZmYsICJVUCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID4gLWRpZmZDdXRvZmYsICJOTyIsICJET1dOIikpKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBBbm5vMkxpc3QpCiAgZGF0YSR1cGRvd25fZFRBR19ETVNPIDwtIGZhY3RvcihkYXRhJHVwZG93bl9kVEFHX0RNU08sIGxldmVscyA9IGMoIlVQIiwgIk5PIiwgIkRPV04iKSkKICBkYXRhJHVwZG93bl9BNDg1X0RNU08gPC0gZmFjdG9yKGRhdGEkdXBkb3duX0E0ODVfRE1TTywgbGV2ZWxzID0gYygiVVAiLCAiTk8iLCAiRE9XTiIpKQogIAogIG91dC50ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX2RUQUdfRE1TTyA9PSAiVVAiKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDQsIDUsIDYpKQogIGZ3cml0ZShvdXQudGVtcCwgaGVyZShvdXREaXIsIHBhc3RlMChuYW1lLCAiX2RUQUd2c0RNU09fVVBfZGlmZiIsIGRpZmZDdXRvZmYsICIuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKICBvdXQudGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9kVEFHX0RNU08gPT0gIk5PIikgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2KSkKICBmd3JpdGUob3V0LnRlbXAsIGhlcmUob3V0RGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHdnNETVNPX05PX2RpZmYiLCBkaWZmQ3V0b2ZmLCAiLmJlZHBlIikpLCAKICAgICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCiAgb3V0LnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fZFRBR19ETVNPID09ICJET1dOIikgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2KSkKICBmd3JpdGUob3V0LnRlbXAsIGhlcmUob3V0RGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHdnNETVNPX0RPV05fZGlmZiIsIGRpZmZDdXRvZmYsICIuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKICAKICBvdXQudGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHVwZG93bl9BNDg1X0RNU08gPT0gIlVQIikgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2KSkKICBmd3JpdGUob3V0LnRlbXAsIGhlcmUob3V0RGlyLCBwYXN0ZTAobmFtZSwgIl9BNDg1dnNETVNPX1VQX2RpZmYiLCBkaWZmQ3V0b2ZmLCAiLmJlZHBlIikpLCAKICAgICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCiAgb3V0LnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcih1cGRvd25fQTQ4NV9ETVNPID09ICJOTyIpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNikpCiAgZndyaXRlKG91dC50ZW1wLCBoZXJlKG91dERpciwgcGFzdGUwKG5hbWUsICJfQTQ4NXZzRE1TT19OT19kaWZmIiwgZGlmZkN1dG9mZiwgIi5iZWRwZSIpKSwgCiAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQogIG91dC50ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIodXBkb3duX0E0ODVfRE1TTyA9PSAiRE9XTiIpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNikpCiAgZndyaXRlKG91dC50ZW1wLCBoZXJlKG91dERpciwgcGFzdGUwKG5hbWUsICJfQTQ4NXZzRE1TT19ET1dOX2RpZmYiLCBkaWZmQ3V0b2ZmLCAiLmJlZHBlIikpLCAKICAgICAgICAgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCn0KYGBgCgojIyMjIERpc3RhbmNlIHZzIHNjb3JlIHBsb3QKIyMjIyMgZFRBRwojIyMjIyMgT0UKYGBge3J9CiMgSW1wb3J0IGFubm90YXRpb24KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQoKIyBJbXBvcnQgb2JzL2V4cCBzY29yZXMgYW5kIG1lcmdlIHRvIHRoZSBkYXRhc2V0Cm1pblZhbHVlIDwtIC00Cm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCiMgTWVyZ2UgZGF0YXNldApkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpCgojIFBsb3QKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgbG9nX29ic2V4cF9ETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnRfb2UodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9ETVNPX2xvZ09FIiksIHVuaXF1ZShkYXRhJEFubm8yKSwgY29sb3JMaXN0TG9vcCkKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSkgJT4lIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGxvZ19vYnNleHBfZFRBRywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnU2NvcmVfcGVyVHJlYXRtZW50X29lKHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfZFRBR19sb2dPRSIpLCB1bmlxdWUoZGF0YSRBbm5vMiksIGNvbG9yTGlzdExvb3ApCgoKIyBDcmVhdGluZyBmaWd1cmVzIHBlciBlYWNoIGNvbmRpdGlvbiwgZGlmZmVyZW50aWFsCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZShkaXN0YW5jZSA9IHN0YXJ0MiAtIHN0YXJ0MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPSBsb2dfb2JzZXhwX2RUQUcgLSBsb2dfb2JzZXhwX0RNU08pICU+JSAKICBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdEaWZmU2NvcmVfcGVyVHJlYXRtZW50X29lKHRlbXAsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfZFRBR19sb2dPRSIpLCB1bmlxdWUoZGF0YSRBbm5vMiksIGNvbG9yTGlzdExvb3ApCmBgYAoKIyMjIyMjIE9FLCBncm91cGVkCmBgYHtyfQojIEltcG9ydCBhbm5vdGF0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKCiMgSW1wb3J0IG9icy9leHAgc2NvcmVzIGFuZCBtZXJnZSB0byB0aGUgZGF0YXNldAptaW5WYWx1ZSA8LSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSkpCgojIE1lcmdlIGRhdGFzZXQKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKG9ic2V4cCwgYnkgPSBjKCJpZCIpKQoKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTykgJT4lIAogIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08sIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCgoKCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShBbm5vMyA9IGNhc2Vfd2hlbihBbm5vMiAlaW4lIGMoIlMtWCIsICJTLVMiKSB+ICJTdHJ1Y3R1cmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFubm8yICVpbiUgYygiUC1QIiwgIlAtRSIsICJFLUUiKSB+ICJQdXJlX1JlZ3VsYXRvcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQW5ubzIgJWluJSBjKCJQLVMiLCAiUC1YIiwgIkUtUyIsICJFLVgiKSB+ICJSZWxheGVkX1JlZ3VsYXRvcnkiKSkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoQW5ubzMpKQoKbG9vcExpc3QgPC0gcmV2KGMoIlN0cnVjdHVyYWwiLCAiUmVsYXhlZF9SZWd1bGF0b3J5IiwgIlB1cmVfUmVndWxhdG9yeSIpKQpjb2xvckxpc3QgPC0gcmV2KGMocGFsZXR0ZV8zW1siZ3JleTIiXV0sIHN0cm9uZ19ncmVlbiwgZGFya2VuKHN0cm9uZ19ncmVlbiwgYW1vdW50ID0gMC41KSkpCmF2Z19zY29yZXNfbG9uZyA8LSB0ZW1wICU+JQogIGdyb3VwX2J5KGRpc3RhbmNlLCBBbm5vMykgJT4lCiAgc3VtbWFyaXNlKGF2Z19zY29yZSA9IG1lYW4oc2NvcmUsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAKYXZnX3Njb3Jlc19sb25nJEFubm8zIDwtIGZhY3Rvcihhdmdfc2NvcmVzX2xvbmckQW5ubzMsIGxldmVsID0gbG9vcExpc3QpCgpwNCA8LSBnZ3Bsb3QoYXZnX3Njb3Jlc19sb25nLCBhZXMoeCA9IGRpc3RhbmNlLCB5ID0gYXZnX3Njb3JlLCBjb2xvciA9IEFubm8zKSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsKICBnZW9tX3Ntb290aChzaG93LmxlZ2VuZCA9IFRSVUUsIHNlID0gVFJVRSwKICAgICAgICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgYWVzKGZpbGwgPSBBbm5vMykpICArCiAgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2tiX21iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yTGlzdCkgKwogIGxhYnMoeCA9ICJMb29wIHNpemUiLAogICAgICAgeSA9ICLOlCBsb2cyKG9icy9leHApIiwKICAgICAgIGNvbG9yID0gIkxvb3AgdHlwZXMiLCBmaWxsID0gIkxvb3AgdHlwZXMiKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKAogICAgICBrZXl3aWR0aCA9IDAuNSwgICMgQWRqdXN0IHRoZSB3aWR0aCBvZiB0aGUgbGVnZW5kIGNvbG9yIHNxdWFyZXMKICAgICAga2V5aGVpZ2h0ID0gMC41ICAjIEFkanVzdCB0aGUgaGVpZ2h0IG9mIHRoZSBsZWdlbmQgY29sb3Igc3F1YXJlcwogICAgKQogICkKCgoKCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImRpc3RfdnNfc2NvcmVfZGlmZmxpbmVQbG90X2dyb3VwZWQiLCBuYW1lKQoKd2lkdGggPC0gcGFuZWxTaXplKDIuNSkqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjI1KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIAogICAgcmVzID0gNjAwLCB1bml0cyA9ICJpbiIsIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9IGhlaWdodCkKcHJpbnQocDQpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAKICAgICAgICB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQpCnByaW50KHA0KQpkZXYub2ZmKCkKCgoKYGBgCgojIyMjIyMgT2JzZXJ2ZWQKYGBge3J9CiMgSW1wb3J0IGFubm90YXRpb24KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGF0YSA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICIudHN2IikpKQoKIyBJbXBvcnQgb2JzL2V4cCBzY29yZXMgYW5kIG1lcmdlIHRvIHRoZSBkYXRhc2V0Cm1pblZhbHVlIDwtIC00Cm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic19ETVNPID0gaWZfZWxzZShvYnNfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzX2RUQUcgPSBpZl9lbHNlKG9ic19kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic19kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNfQTQ4NSA9IGlmX2Vsc2Uob2JzX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzX0E0ODUpKSkKCiMgTWVyZ2UgZGF0YXNldApkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpCgojIFBsb3QKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKSAlPiUgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgbG9nX29ic19ETVNPLCBBbm5vMikKY29sbmFtZXModGVtcCkgPC0gYygiZGlzdGFuY2UiLCAic2NvcmUiLCAiQW5ubzIiKQpjcmVhdGVfZGlzdF92c19hdmdTY29yZV9wZXJUcmVhdG1lbnRfb2UodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9ETVNPX2xvZ09icyIpLCB1bmlxdWUoZGF0YSRBbm5vMiksIGNvbG9yTGlzdExvb3ApCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBsb2dfb2JzX2RUQUcsIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z1Njb3JlX3BlclRyZWF0bWVudF9vZSh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2RUQUdfbG9nT2JzIiksIHVuaXF1ZShkYXRhJEFubm8yKSwgY29sb3JMaXN0TG9vcCkKCgojIENyZWF0aW5nIGZpZ3VyZXMgcGVyIGVhY2ggY29uZGl0aW9uLCBkaWZmZXJlbnRpYWwKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nX29ic19kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNfZFRBRyAtIGxvZ19vYnNfRE1TTykgJT4lIAogIGRwbHlyOjpzZWxlY3QoZGlzdGFuY2UsIGxvZ19vYnNfZGlmZl9kVEFHX0RNU08sIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z0RpZmZTY29yZV9wZXJUcmVhdG1lbnRfb2UodGVtcCwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9kVEFHX2xvZ09icyIpLCB1bmlxdWUoZGF0YSRBbm5vMiksIGNvbG9yTGlzdExvb3ApCmBgYAoKIyMjIyMgQTQ4NQpgYGB7cn0KIyBJbXBvcnQgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCgojIEltcG9ydCBvYnMvZXhwIHNjb3JlcyBhbmQgbWVyZ2UgdG8gdGhlIGRhdGFzZXQKbWluVmFsdWUgPC0gLTQKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogICAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZFRBRyA9IGlmX2Vsc2Uob2JzZXhwX2RUQUcgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX2RUQUcpKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpKQoKIyBNZXJnZSBkYXRhc2V0CmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkKCiMgUGxvdAp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpICU+JSBkcGx5cjo6c2VsZWN0KGRpc3RhbmNlLCBsb2dfb2JzZXhwX0E0ODUsIEFubm8yKQpjb2xuYW1lcyh0ZW1wKSA8LSBjKCJkaXN0YW5jZSIsICJzY29yZSIsICJBbm5vMiIpCmNyZWF0ZV9kaXN0X3ZzX2F2Z1Njb3JlX3BlclRyZWF0bWVudF9vZSh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODVfbG9nT0UiKSwgdW5pcXVlKGRhdGEkQW5ubzIpLCBjb2xvckxpc3RMb29wKQoKCiMgQ3JlYXRpbmcgZmlndXJlcyBwZXIgZWFjaCBjb25kaXRpb24sIGRpZmZlcmVudGlhbAp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID0gbG9nX29ic2V4cF9BNDg1IC0gbG9nX29ic2V4cF9ETVNPKSAlPiUgCiAgZHBseXI6OnNlbGVjdChkaXN0YW5jZSwgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTywgQW5ubzIpCmNvbG5hbWVzKHRlbXApIDwtIGMoImRpc3RhbmNlIiwgInNjb3JlIiwgIkFubm8yIikKY3JlYXRlX2Rpc3RfdnNfYXZnRGlmZlNjb3JlX3BlclRyZWF0bWVudF9vZSh0ZW1wLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX0E0ODVfbG9nT0UiKSwgdW5pcXVlKGRhdGEkQW5ubzIpLCBjb2xvckxpc3RMb29wKQpgYGAKCiMjIyMgR2V0IHNpemUgZGlzdHJpYnV0aW9uIG9mIGRpZmZlcmVudGlhbCBsb29wcwpgYGB7cn0KIyBJbXBvcnQgYW5ub3RhdGlvbgpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgpkYXRhIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIi50c3YiKSkpCgojIEltcG9ydCBvYnMvZXhwIHNjb3JlcyBhbmQgbWVyZ2UgdG8gdGhlIGRhdGFzZXQKbWluVmFsdWUgPSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfRE1TTyA9IGlmX2Vsc2Uob2JzZXhwX0RNU08gPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0RNU08pKSwKICAgICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSkpCgojIE1lcmdlIGRhdGFzZXQKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKG9ic2V4cCwgYnkgPSBjKCJpZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08gPSBsb2dfb2JzZXhwX2RUQUcgLSBsb2dfb2JzZXhwX0RNU08sCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPID0gbG9nX29ic2V4cF9BNDg1IC0gbG9nX29ic2V4cF9ETVNPKQoKZGlmZkN1dG9mZiA8LSAwLjUKY3JlYXRlX2xvb3Bfc2NhdHRlcnBsb3Rfb2UoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9sb2dPRV8iLCAiYWxsIiksIHVuaXF1ZShkYXRhJEFubm8yKSwgZGlmZkN1dG9mZikKY3JlYXRlX2xvb3Bfc2NhdHRlcnBsb3Rfb2UoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9sb2dPRV8iLCAicmVnIiksIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIGRpZmZDdXRvZmYpCmNyZWF0ZV9sb29wX3NjYXR0ZXJwbG90X29lKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfbG9nT0VfIiwgInN0ciIpLCBjKCJTLVMiLCAiUy1YIiksIGRpZmZDdXRvZmYpCgoKCmNyZWF0ZV9kaXN0X2JhcnBsb3Rfb2UoZGF0YSwgZmlnRGlyLCBwYXN0ZTAobmFtZSwgIl9sb2dPRSIpLCAiYWxsIiwgIHVuaXF1ZShkYXRhJEFubm8yKSwgZGlmZkN1dG9mZikKY3JlYXRlX2Rpc3RfYmFycGxvdF9vZShkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2xvZ09FIiksICJyZWciLCAgYygiUC1QIiwgIlAtRSIsICJFLUUiKSwgZGlmZkN1dG9mZikKY3JlYXRlX2Rpc3RfYmFycGxvdF9vZShkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2xvZ09FIiksICJyZWdfMW1iIiwgIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIGRpZmZDdXRvZmYsIDFlNikKY3JlYXRlX2Rpc3RfYmFycGxvdF9vZShkYXRhLCBmaWdEaXIsIHBhc3RlMChuYW1lLCAiX2xvZ09FIiksICJzdHIiLCAgYygiUy1TIiwgIlMtWCIpLCBkaWZmQ3V0b2ZmKQpjcmVhdGVfZGlzdF9iYXJwbG90X29lKGRhdGEsIGZpZ0RpciwgcGFzdGUwKG5hbWUsICJfbG9nT0UiKSwgInN0cl8xbWIiLCAgYygiUy1TIiwgIlMtWCIpLCBkaWZmQ3V0b2ZmLCAxZTYpCgpgYGAKIyMjIyBTcGxpdHRpbmcgbG9vcHMgaW50byBkaWZmIGJlZHBlCmBgYHtyfQojIEltcG9ydCBhbm5vdGF0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRhdGEgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiLnRzdiIpKSkKCiMgSW1wb3J0IG9icy9leHAgc2NvcmVzIGFuZCBtZXJnZSB0byB0aGUgZGF0YXNldAptaW5WYWx1ZSA9IC00Cm9ic2V4cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKCJsb29wU2NvcmVfY29uc19vYnNleHAudHN2IikpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfQTQ4NSA9IGlmX2Vsc2Uob2JzZXhwX0E0ODUgPT0gMCwgbWluVmFsdWUsIGxvZzIob2JzZXhwX0E0ODUpKSkKCiMgTWVyZ2UgZGF0YXNldApkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTywKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPSBsb2dfb2JzZXhwX0E0ODUgLSBsb2dfb2JzZXhwX0RNU08pCmRpZmZDdXRvZmYgPC0gMC41Cm1ha2VfZGlmZl9iZWRwZV9vZShkYXRhLCBwYXN0ZTAobmFtZSwgIl9sb2dPRV8iLCAiYWxsIiksIHVuaXF1ZShkYXRhJEFubm8yKSwgY29uc2Vuc3VzRGlyLCBkaWZmQ3V0b2ZmKQptYWtlX2RpZmZfYmVkcGVfb2UoZGF0YSwgcGFzdGUwKG5hbWUsICJfbG9nT0VfIiwgInBlLXBlIiksIGMoIlAtUCIsICJQLUUiLCAiRS1FIiksIGNvbnNlbnN1c0RpciwgZGlmZkN1dG9mZikKbWFrZV9kaWZmX2JlZHBlX29lKGRhdGEsIHBhc3RlMChuYW1lLCAiX2xvZ09FXyIsICJzdHIiKSwgYygiUy1TIiwgIlMtWCIpLCBjb25zZW5zdXNEaXIsIGRpZmZDdXRvZmYpCgpgYGAKCiMjIyBbMi4yN10gRXh0cmFjdGluZyBUU1MgZm9yIGRlZXB0b29scwpgYGB7cn0KZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpmbGFua1NpemUgPC0gMQpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNikKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJlbnNlbWJsIikKCmJlZC4xIDwtIGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGdyb3VwMSkgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKYmVkLjIgPC0gZ2VuZS50YiAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsICVpbiUgZ3JvdXAyKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQoKZndyaXRlKGJlZC4xLCBoZXJlKHJlZkRpciwgIlRTU19iaW5hcnlHcm91cDEuYmVkIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQpmd3JpdGUoYmVkLjIsIGhlcmUocmVmRGlyLCAiVFNTX2JpbmFyeUdyb3VwMi5iZWQiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCgoKCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkKCmJlZC4xIDwtIGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoVjYgJWluJSBncm91cDEpCmJlZC4yIDwtIGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoVjYgJWluJSBncm91cDIpCgpmd3JpdGUoYmVkLjEsIGhlcmUocmVmRGlyLCAiVFNTX2JpbmFyeUdyb3VwMV9ndGYuYmVkIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQpmd3JpdGUoYmVkLjIsIGhlcmUocmVmRGlyLCAiVFNTX2JpbmFyeUdyb3VwMl9ndGYuYmVkIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQoKYGBgCgojIyMgWzIuMjhdIENoZWNraW5nIGdlbmUgZXhwcmVzc2lvbiBsZXZlbHMgb2YgYmluYXJ5R3JvdXAKYGBge3J9Cmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKZGF0YSA8LSBmcmVhZChoZXJlKHJlZkRpciwgInJlYWRDb3VudC5maWx0ZXJlZC5UUE0uYWxsLnRzdiIpKSAlPiUgZHBseXI6Om11dGF0ZSgKICBncm91cCA9IGNhc2Vfd2hlbihlbnNlbWJsICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgICAgICAgICAgICAgICAgICAgZW5zZW1ibCAlaW4lIGdyb3VwMiB+ICJncm91cDIiLAogICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkKKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpICU+JQogIGRwbHlyOjpzZWxlY3QoYygzNCwgMSwgMywgNCwgNSwgMTQsIDE1LCAzNCkpCgpkYXRhIDwtIGRhdGEgJT4lIG11dGF0ZShhdmVyYWdlID0gcm93TWVhbnMoYWNyb3NzKGNvbG5hbWVzKGRhdGEpWzM6N10pKSkKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgYXZlcmFnZSkKCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkYXZlcmFnZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRhdmVyYWdlCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKcHZhbCA8LSBjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgImdyb3VwMSIsICJncm91cDIiKSkKCmdncGxvdCh0ZW1wLCBhZXMoeCA9IGdyb3VwLCB5ID0gYXZlcmFnZSkpICsgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV95X2xvZzEwKCkgKwogIHlsYWIoImF2Z1RQTSIpICsgdGhlbWVfY2xhc3NpYygpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMTAwMDAsIGxhYmVsID0gcHZhbCkKCgoKCmBgYAoKIyMjIFsyLjI5XSBDaGVja2luZyBvdmVybGFwIHdpdGggU3RyaXBlcwpgYGB7cn0KZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpmbGFua1NpemUgPC0gMQpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNikKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJlbnNlbWJsIikKCmJlZC4xIDwtIGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGdyb3VwMSkgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKYmVkLjIgPC0gZ2VuZS50YiAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsICVpbiUgZ3JvdXAyKSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQoKCmRhdGEgPC0gZnJlYWQoaGVyZSgiLi4vLi4iLCAicmVzdWx0IiwgInN0cmlwZW5uIiwgInJlc3VsdF9maWx0ZXJlZC50c3YiKSkKCmdncGxvdChkYXRhLCBhZXMoeCA9IHdpZHRoKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgdGhlbWVfY2xhc3NpYygpICsKIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikKCgojIyBDaGVja2luZyBvdmVybGFwIHdpdGggZ2VuZSBUU1MKCnRzcyA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X1RTUzIuNWtiLmJlZCIpKQoKdHNzLmdyb3VwMSA8LSB0c3MgJT4lIGRwbHlyOjpmaWx0ZXIoVjYgJWluJSBncm91cDEpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKHRzcy5ncm91cDEpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQp0c3MuZ3JvdXAxLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0c3MuZ3JvdXAxKQoKdHNzLmdyb3VwMiA8LSB0c3MgJT4lIGRwbHlyOjpmaWx0ZXIoVjYgJWluJSBncm91cDIpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKHRzcy5ncm91cDIpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQp0c3MuZ3JvdXAyLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0c3MuZ3JvdXAyKQoKIyMgQW5jaG9yIG9mIHN0cmlwZXMKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KGNociwgcG9zMSwgcG9zMikKY29sbmFtZXModGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCgpzdHJpcGVBbmNob3IuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgpvdmVybGFwLmdyb3VwMSA8LSBmaW5kT3ZlcmxhcHModHNzLmdyb3VwMS5nciwgc3RyaXBlQW5jaG9yLmdyKQpvdmVybGFwLmdyb3VwMiA8LSBmaW5kT3ZlcmxhcHModHNzLmdyb3VwMi5nciwgc3RyaXBlQW5jaG9yLmdyKQoKbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5ncm91cDEpKSkKbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5ncm91cDIpKSkKCgojIyBib2R5IG9mIHN0cmlwZXMKdGVtcCA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KGNociwgcG9zMywgcG9zNCkKY29sbmFtZXModGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCgpzdHJpcGVCb2R5LmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0ZW1wKQoKb3ZlcmxhcC5ncm91cDEgPC0gZmluZE92ZXJsYXBzKHRzcy5ncm91cDEuZ3IsIHN0cmlwZUJvZHkuZ3IpCm92ZXJsYXAuZ3JvdXAyIDwtIGZpbmRPdmVybGFwcyh0c3MuZ3JvdXAyLmdyLCBzdHJpcGVCb2R5LmdyKQoKbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5ncm91cDEpKSkKbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5ncm91cDIpKSkKCiMjIENoZWNraW5nIFJBRDIxL0NUQ0YgcHJlc2VuY2UgYXQgYW5jaG9yCm92ZXJsYXAuYm9keS5jdGNmIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVCb2R5LmdyLCBwZWFrLkNUQ0YpCm92ZXJsYXAuYm9keS5yYWQyMSA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQm9keS5nciwgcGVhay5SQUQyMSkKb3ZlcmxhcC5hbmNob3IuY3RjZiA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQW5jaG9yLmdyLCBwZWFrLkNUQ0YpCm92ZXJsYXAuYW5jaG9yLnJhZDIxIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVBbmNob3IuZ3IsIHBlYWsuUkFEMjEpCgpsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhvdmVybGFwLmJvZHkuY3RjZikpKQpsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhvdmVybGFwLmJvZHkucmFkMjEpKSkKCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAuYW5jaG9yLmN0Y2YpKSkKbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5hbmNob3IucmFkMjEpKSkKICAKIyMgQ2hlY2tpbmcgb3ZlcmxhcCB3aXRoIGxvb3AgYW5jaG9yIChQRS1QRSkKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IudXBubyA8LSBleHRyYWN0QW5jaG9yKGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLmRvd24gPC0gZXh0cmFjdEFuY2hvcihsb29wLmRvd24pCgoKb3ZlcmxhcC5ib2R5LnVwbm8gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUJvZHkuZ3IsIGFuY2hvci51cG5vKQpvdmVybGFwLmJvZHkuZG93biA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQm9keS5nciwgYW5jaG9yLmRvd24pCm92ZXJsYXAuYW5jaG9yLnVwbm8gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUFuY2hvci5nciwgYW5jaG9yLnVwbm8pCm92ZXJsYXAuYW5jaG9yLmRvd24gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUFuY2hvci5nciwgYW5jaG9yLmRvd24pCgpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYm9keS51cG5vKSkpCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5ib2R5LmRvd24pKSkKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmFuY2hvci51cG5vKSkpCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5hbmNob3IuZG93bikpKQoKCiMjIENoZWNraW5nIG92ZXJsYXAgd2l0aCBsb29wIGFuY2hvciAoQUxMKQpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwbm8gPC0gZXh0cmFjdEFuY2hvcihiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykpCgpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSBleHRyYWN0QW5jaG9yKGxvb3AuZG93bikKCgpvdmVybGFwLmJvZHkudXBubyA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQm9keS5nciwgYW5jaG9yLnVwbm8pCm92ZXJsYXAuYm9keS5kb3duIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVCb2R5LmdyLCBhbmNob3IuZG93bikKb3ZlcmxhcC5hbmNob3IudXBubyA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQW5jaG9yLmdyLCBhbmNob3IudXBubykKb3ZlcmxhcC5hbmNob3IuZG93biA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQW5jaG9yLmdyLCBhbmNob3IuZG93bikKCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5ib2R5LnVwbm8pKSkKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmJvZHkuZG93bikpKQpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYW5jaG9yLnVwbm8pKSkKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmFuY2hvci5kb3duKSkpCgoKIyMgQ2hlY2tpbmcgb3ZlcmxhcCB3aXRoIGxvb3AgYW5jaG9yIChTdHJ1Y3R1cmUpCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3N0cnVjdHVyZV9kVEFHdnNETVNPX1VQX2RpZmYwLjIuYmVkcGUiKSkKbG9vcC5ubyA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IudXBubyA8LSBleHRyYWN0QW5jaG9yKGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5kb3duIDwtIGV4dHJhY3RBbmNob3IobG9vcC5kb3duKQoKb3ZlcmxhcC5ib2R5LnVwbm8gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUJvZHkuZ3IsIGFuY2hvci51cG5vKQpvdmVybGFwLmJvZHkuZG93biA8LSBmaW5kT3ZlcmxhcHMoc3RyaXBlQm9keS5nciwgYW5jaG9yLmRvd24pCm92ZXJsYXAuYW5jaG9yLnVwbm8gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUFuY2hvci5nciwgYW5jaG9yLnVwbm8pCm92ZXJsYXAuYW5jaG9yLmRvd24gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUFuY2hvci5nciwgYW5jaG9yLmRvd24pCgpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYm9keS51cG5vKSkpCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5ib2R5LmRvd24pKSkKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmFuY2hvci51cG5vKSkpCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5hbmNob3IuZG93bikpKQoKCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5ib2R5LnVwbm8pKSkvbGVuZ3RoKGFuY2hvci51cG5vKSoxMDAKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmJvZHkuZG93bikpKS9sZW5ndGgoYW5jaG9yLmRvd24pKjEwMApsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYW5jaG9yLnVwbm8pKSkvbGVuZ3RoKGFuY2hvci51cG5vKSoxMDAKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmFuY2hvci5kb3duKSkpL2xlbmd0aChhbmNob3IuZG93bikqMTAwCgoKIyMgQ2hlY2tpbmcgb3ZlcmxhcCB3aXRoIGxvb3AgYW5jaG9yIChSZWxheGVkUmVnKQpsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9yZWd1bGF0b3J5X2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9yZWd1bGF0b3J5X2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IudXBubyA8LSBleHRyYWN0QW5jaG9yKGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcmVndWxhdG9yeV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSBleHRyYWN0QW5jaG9yKGxvb3AuZG93bikKCm92ZXJsYXAuYm9keS51cG5vIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVCb2R5LmdyLCBhbmNob3IudXBubykKb3ZlcmxhcC5ib2R5LmRvd24gPC0gZmluZE92ZXJsYXBzKHN0cmlwZUJvZHkuZ3IsIGFuY2hvci5kb3duKQpvdmVybGFwLmFuY2hvci51cG5vIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVBbmNob3IuZ3IsIGFuY2hvci51cG5vKQpvdmVybGFwLmFuY2hvci5kb3duIDwtIGZpbmRPdmVybGFwcyhzdHJpcGVBbmNob3IuZ3IsIGFuY2hvci5kb3duKQoKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmJvZHkudXBubykpKQpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYm9keS5kb3duKSkpCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5hbmNob3IudXBubykpKQpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYW5jaG9yLmRvd24pKSkKCgpsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKG92ZXJsYXAuYm9keS51cG5vKSkpL2xlbmd0aChhbmNob3IudXBubykqMTAwCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5ib2R5LmRvd24pKSkvbGVuZ3RoKGFuY2hvci5kb3duKSoxMDAKbGVuZ3RoKHVuaXF1ZShzdWJqZWN0SGl0cyhvdmVybGFwLmFuY2hvci51cG5vKSkpL2xlbmd0aChhbmNob3IudXBubykqMTAwCmxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHMob3ZlcmxhcC5hbmNob3IuZG93bikpKS9sZW5ndGgoYW5jaG9yLmRvd24pKjEwMAoKCgoKYGBgCgojIyMgWzIuMzBdIEh1YnMgZnJvbSBEeWxhbiBQYXBlcgojIyMjIEFsbCBsb29wcwpgYGB7cn0KcmVzdWx0cyA8LSB0aWJibGUoaSA9IG51bWVyaWMoKSwgdXBubyA9IG51bWVyaWMoKSwgZG93biA9IG51bWVyaWMoKSkKCmZvcihpIGluIHNlcSgxLCAxMCkpewogIGRhdGEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJEeWxhbl9odWJfZXNjLmNzdiIpKQogIAogIGRhdGEuaHViIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoYWxsX2xjb24gPiBpKQogIHRlbXAgPC0gZGF0YS5odWIgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKICBjb2xuYW1lcyh0ZW1wKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICBodWIuYW5jaG9yIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0ZW1wKQogIAogIAogIApsb29wLnVwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9hbGxfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwbm8gPC0gZXh0cmFjdEFuY2hvcihiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykpCgpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X2FsbF9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKQphbmNob3IuZG93biA8LSBleHRyYWN0QW5jaG9yKGxvb3AuZG93bikKCiAgCiAgb3ZlcmxhcC51cG5vIDwtIGZpbmRPdmVybGFwcyhhbmNob3IudXBubywgaHViLmFuY2hvcikKICBvdmVybGFwLmRvd24gPC0gZmluZE92ZXJsYXBzKGFuY2hvci5kb3duLCBodWIuYW5jaG9yKQogIAogIG4xIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAudXBubykpKQogIG4yIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAuZG93bikpKQogIAogIHBlcmMxIDwtIHJvdW5kKG4xL2xlbmd0aChvdmVybGFwLnVwbm8pKjEwMCwgMikKICBwZXJjMiA8LSByb3VuZChuMi9sZW5ndGgob3ZlcmxhcC5kb3duKSoxMDAsIDIpCiAgCiAgcmVzdWx0cyA8LSByZXN1bHRzICU+JSBhZGRfcm93KGkgPSBpLCB1cG5vID0gcGVyYzEsIGRvd24gPSBwZXJjMikKfQoKCgpyZXN1bHRzX2xvbmcgPC0gcmVzdWx0cyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGModXBubywgZG93biksIG5hbWVzX3RvID0gIkdyb3VwIiwgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2UiKQoKcmVzdWx0c19sb25nJEdyb3VwIDwtIGZhY3RvcihyZXN1bHRzX2xvbmckR3JvdXAsIGxldmVscyA9IGMoInVwbm8iLCAiZG93biIpKQojIENyZWF0ZSB0aGUgYmFyIHBsb3QKZ2dwbG90KHJlc3VsdHNfbG9uZywgYWVzKHggPSBmYWN0b3IoaSksIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJBbGwgbG9vcHMiLAogICAgeCA9ICJQcmVzZW5jZSBvZiBodWIgYW5jaG9yIHdpdGggPmkgY29ubmVjdGlvbnMiLAogICAgeSA9ICJQZXJjZW50YWdlIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygidXBubyIgPSAiYmx1ZSIsICJkb3duIiA9ICJyZWQiKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgeWxpbSgwLCAxMDApCmBgYAoKIyMjIyMgRmlzaGVycwpgYGB7cn0KbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19VUF9kaWZmMC4yLmJlZHBlIikpCmxvb3Aubm8gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fTk9fZGlmZjAuMi5iZWRwZSIpKQpsb29wLnVwbm8gPC0gKGJpbmRfcm93cyhsb29wLnVwLCBsb29wLm5vKSkKCmxvb3AuZG93biA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfcGUtcGVfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkKCmdldE92ZXJsYXBMb29wTnVtIDwtIGZ1bmN0aW9uKGxvb3AsIHBlYWspewogIGFuY2hvcjEgPC0gR1JhbmdlcyhzZXFuYW1lcyA9IGxvb3AkVjEsIHJhbmdlcyA9IElSYW5nZXMoc3RhcnQgPSBsb29wJFYyLCBlbmQgPSBsb29wJFYzKSkKICBhbmNob3IyIDwtIEdSYW5nZXMoc2VxbmFtZXMgPSBsb29wJFY0LCByYW5nZXMgPSBJUmFuZ2VzKHN0YXJ0ID0gbG9vcCRWNSwgZW5kID0gbG9vcCRWNikpCiAgYSA8LSBxdWVyeUhpdHMoZmluZE92ZXJsYXBzKGFuY2hvcjEsIHBlYWspKQogIGIgPC0gcXVlcnlIaXRzKGZpbmRPdmVybGFwcyhhbmNob3IyLCBwZWFrKSkKICByZXR1cm4obGVuZ3RoKHVuaXF1ZShjKGEsIGIpKSkpCn0KCmdldFNFT3ZlcmxhcEZpc2hlciA8LSBmdW5jdGlvbihhbGxMb29wLCBzdWJzZXRMb29wLCBwZWFrKXsKICBhbGwub3ZlcmxhcCA8LSBnZXRPdmVybGFwTG9vcE51bShhbGxMb29wLCBwZWFrKQogIGFsbC5ub3RPdmVybGFwIDwtIG5yb3coYWxsTG9vcCkgLSBhbGwub3ZlcmxhcAogIAogIHN1YnNldC5vdmVybGFwIDwtIGdldE92ZXJsYXBMb29wTnVtKHN1YnNldExvb3AsIHBlYWspCiAgc3Vic2V0Lm5vdE92ZXJsYXAgPC0gbnJvdyhzdWJzZXRMb29wKSAtIHN1YnNldC5vdmVybGFwCiAgCiAgY29udGluZ2VuY3lfdGFibGUgPC0gbWF0cml4KGMoc3Vic2V0Lm92ZXJsYXAsIHN1YnNldC5ub3RPdmVybGFwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbC5vdmVybGFwLCBhbGwubm90T3ZlcmxhcCksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpCiAgY29sbmFtZXMoY29udGluZ2VuY3lfdGFibGUpIDwtIGMoIk92ZXJsYXBwaW5nIiwgIk5vdF9PdmVybGFwcGluZyIpCiAgcm93bmFtZXMoY29udGluZ2VuY3lfdGFibGUpIDwtIGMoIkFsbCBsb29wcyIsICJTdWJzZXQgbG9vcHMiKQogIAogICMgUGVyZm9ybSBGaXNoZXIncyBFeGFjdCBUZXN0CiAgZmlzaGVyX3Rlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQogIHJldHVybihmaXNoZXJfdGVzdF9yZXN1bHQpCn0KCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmxvb3AgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlLmJlZHBlIikpCgoKaSA8LSAyCmRhdGEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJEeWxhbl9odWJfZXNjLmNzdiIpKQoKZGF0YS5odWIgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihhbGxfbGNvbiA+IGkpCnRlbXAgPC0gZGF0YS5odWIgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzKSkKY29sbmFtZXModGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCmh1Yi5hbmNob3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgoKdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC51cG5vLCBodWIuYW5jaG9yKQpyZXN1bHQudGIgPC0gdGliYmxlKGxvb3BUeXBlID0gIlVQL05PIiwKICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAoImh1Yl8iLCBpKSwKICAgICAgICAgICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICAgICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC5kb3duLCBodWIuYW5jaG9yKQpyZXN1bHQudGIgPC0gcmVzdWx0LnRiICU+JSAKICBhZGRfcm93KGxvb3BUeXBlID0gIkRPV04iLAogICAgICAgICAgdGFyZ2V0ID0gIHBhc3RlMCgiaHViXyIsIGkpLAogICAgICAgICAgcHZhbHVlID0gdGVtcCRwLnZhbHVlLAogICAgICAgICAgb2Rkc1JhdGlvID0gdGVtcCRlc3RpbWF0ZSkKCgpmb3IoaSBpbiBjKDUpKXsKICBkYXRhIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiRHlsYW5faHViX2VzYy5jc3YiKSkKICAKICBkYXRhLmh1YiA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGFsbF9sY29uID4gaSkKICB0ZW1wIDwtIGRhdGEuaHViICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCiAgY29sbmFtZXModGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgaHViLmFuY2hvciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCkKICAKICAKICB0ZW1wIDwtIGdldFNFT3ZlcmxhcEZpc2hlcihsb29wLCBsb29wLnVwbm8sIGh1Yi5hbmNob3IpCiAgcmVzdWx0LnRiIDwtIHJlc3VsdC50YiAlPiUgYWRkX3Jvdyhsb29wVHlwZSA9ICJVUC9OTyIsCiAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQgPSBwYXN0ZTAoImh1Yl8iLCBpKSwKICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZSA9IHRlbXAkcC52YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCiAgdGVtcCA8LSBnZXRTRU92ZXJsYXBGaXNoZXIobG9vcCwgbG9vcC5kb3duLCBodWIuYW5jaG9yKQogIHJlc3VsdC50YiA8LSByZXN1bHQudGIgJT4lIAogICAgYWRkX3Jvdyhsb29wVHlwZSA9ICJET1dOIiwKICAgICAgICAgICAgdGFyZ2V0ID0gIHBhc3RlMCgiaHViXyIsIGkpLAogICAgICAgICAgICBwdmFsdWUgPSB0ZW1wJHAudmFsdWUsCiAgICAgICAgICAgIG9kZHNSYXRpbyA9IHRlbXAkZXN0aW1hdGUpCiAgCiAgCn0KCmxpYnJhcnkoY2lyY2xpemUpCmRhdGEgPC0gcmVzdWx0LnRiCmhlYXRtYXBfZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHRhcmdldCwgbG9vcFR5cGUsIG9kZHNSYXRpbykgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBsb29wVHlwZSwgdmFsdWVzX2Zyb20gPSBvZGRzUmF0aW8pICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAidGFyZ2V0IikKCnB2YWx1ZV9kYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QodGFyZ2V0LCBsb29wVHlwZSwgcHZhbHVlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbG9vcFR5cGUsIHZhbHVlc19mcm9tID0gcHZhbHVlKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInRhcmdldCIpCgojIGNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDIpLCAKIyAgICAgICAgICAgICAgICAgICAgICAgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKCmRhdGEkdGFyZ2V0IDwtIGZhY3RvcihkYXRhJHRhcmdldCwgbGV2ZWxzID0gYygiaHViXzUiLCAiaHViXzIiKSkKZGF0YSRsb29wVHlwZSA8LSBmYWN0b3IoZGF0YSRsb29wVHlwZSwgbGV2ZWxzID0gYygiVVAvTk8iLCAiRE9XTiIpKQpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGxvb3BUeXBlLCB5ID0gdGFyZ2V0LCBzaXplID0gLWxvZzEwKHB2YWx1ZSksIGZpbGwgPSBvZGRzUmF0aW8pKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCAgICAgICAgIyBFbnN1cmVzIGEgcG9pbnQgd2l0aCBhbiBvdXRsaW5lCiAgICAgICAgICAgICBzdHJva2UgPSAxKnB0VG9NTSAgICAgICMgTGluZSB3aWR0aCBmb3IgdGhlIGJvcmRlcgogICkgKyB0aGVtZV9idygpICsgCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCAzKSkgKyAgIyBTZXQgbWluIGFuZCBtYXggcG9pbnQgc2l6ZXMgaGVyZQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiM0ODUyQTAiLCAid2hpdGUiLCAiI0NCMzMzQSIpLCAgIyBEZWZpbmUgZ3JhZGllbnQgY29sb3JzCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoYygwLjUsIDEsIDEuNSkpLCBsaW1pdHMgPSBjKDAuNSwgMS41KSwgCiAgICAgICAgICAgICAgICAgICAgICAjbG93ID0gIndoaXRlIiwgaGlnaCA9ICIjQ0IzMzNBIiwKICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDEsIDMpLAogICAgICAgICAgICAgICAgICAgICAgb29iID0gc2NhbGVzOjpzcXVpc2gsICMgRGVmaW5lIGdyYWRpZW50IGNvbG9ycwogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigKICAgICAgICAgICAgICAgICAgICAgICAgYmFyd2lkdGggPSAxLjUvNS4wOCwgICMgQWRqdXN0IHdpZHRoIG9mIHRoZSBjb2xvciBiYXIKICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gMTUvNS4wOCAgICMgQWRqdXN0IGhlaWdodCBvZiB0aGUgY29sb3IgYmFyCiAgICAgICAgICAgICAgICAgICAgICApCiAgKSArIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSAgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSA0NSwgICAgICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIDQ1IGRlZ3JlZXMKICAgICAgaGp1c3QgPSAxLCAgICAgICAjIEFkanVzdCBob3Jpem9udGFsIGp1c3RpZmljYXRpb24KICAgICAgdmp1c3QgPSAxICAgICAgICAjIEFkanVzdCB2ZXJ0aWNhbCBqdXN0aWZpY2F0aW9uCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKQoKCmZpbGVOYW1lIDwtIGhlcmUoZmlnRGlyLCAiaGVhdG1hcF9odWJfZW5yaWNobWVudF9kb3RwbG90X2FsbCIpCndpZHRoIDwtIHBhbmVsU2l6ZSgxLjY1KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuMSkqbW1Ub0luY2gKIyAjIHBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQojICMgcHJpbnQocCkKIyAjIGRldi5vZmYoKQpzdmdsaXRlKHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKCgojIyMjIFBFLVBFIGxvb3BzCmBgYHtyfQpyZXN1bHRzIDwtIHRpYmJsZShpID0gbnVtZXJpYygpLCB1cG5vID0gbnVtZXJpYygpLCBkb3duID0gbnVtZXJpYygpKQoKZm9yKGkgaW4gc2VxKDEsIDEwKSl7CiAgZGF0YSA8LSBmcmVhZChoZXJlKHJlZkRpciwgIkR5bGFuX2h1Yl9lc2MuY3N2IikpCiAgCiAgZGF0YS5odWIgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihhbGxfbGNvbiA+IGkpCiAgdGVtcCA8LSBkYXRhLmh1YiAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQogIGNvbG5hbWVzKHRlbXApIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQogIGh1Yi5hbmNob3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCiAgCiAgCiAgCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLnVwbm8gPC0gZXh0cmFjdEFuY2hvcihiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykpCgpsb29wLmRvd24gPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fRE9XTl9kaWZmMC4yLmJlZHBlIikpCmFuY2hvci5kb3duIDwtIGV4dHJhY3RBbmNob3IobG9vcC5kb3duKQoKCiAgCiAgb3ZlcmxhcC51cG5vIDwtIGZpbmRPdmVybGFwcyhhbmNob3IudXBubywgaHViLmFuY2hvcikKICBvdmVybGFwLmRvd24gPC0gZmluZE92ZXJsYXBzKGFuY2hvci5kb3duLCBodWIuYW5jaG9yKQogIAogIG4xIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAudXBubykpKQogIG4yIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAuZG93bikpKQogIAogIHBlcmMxIDwtIHJvdW5kKG4xL2xlbmd0aChvdmVybGFwLnVwbm8pKjEwMCwgMikKICBwZXJjMiA8LSByb3VuZChuMi9sZW5ndGgob3ZlcmxhcC5kb3duKSoxMDAsIDIpCiAgCiAgcmVzdWx0cyA8LSByZXN1bHRzICU+JSBhZGRfcm93KGkgPSBpLCB1cG5vID0gcGVyYzEsIGRvd24gPSBwZXJjMikKfQoKCgpyZXN1bHRzX2xvbmcgPC0gcmVzdWx0cyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGModXBubywgZG93biksIG5hbWVzX3RvID0gIkdyb3VwIiwgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2UiKQpyZXN1bHRzX2xvbmckR3JvdXAgPC0gZmFjdG9yKHJlc3VsdHNfbG9uZyRHcm91cCwgbGV2ZWxzID0gYygidXBubyIsICJkb3duIikpCgojIENyZWF0ZSB0aGUgYmFyIHBsb3QKZ2dwbG90KHJlc3VsdHNfbG9uZywgYWVzKHggPSBmYWN0b3IoaSksIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQRS1QRSBsb29wcyIsCiAgICB4ID0gIlByZXNlbmNlIG9mIGh1YiBhbmNob3Igd2l0aCA+aSBjb25uZWN0aW9ucyIsCiAgICB5ID0gIlBlcmNlbnRhZ2UiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJ1cG5vIiA9ICJibHVlIiwgImRvd24iID0gInJlZCIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyB5bGltKDAsIDEwMCkKYGBgCgoKIyMjIyBTdHIgbG9vcHMKYGBge3J9CnJlc3VsdHMgPC0gdGliYmxlKGkgPSBudW1lcmljKCksIHVwbm8gPSBudW1lcmljKCksIGRvd24gPSBudW1lcmljKCkpCgpmb3IoaSBpbiBzZXEoMSwgMTApKXsKICBkYXRhIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiRHlsYW5faHViX2VzYy5jc3YiKSkKICAKICBkYXRhLmh1YiA8LSBkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGFsbF9sY29uID4gaSkKICB0ZW1wIDwtIGRhdGEuaHViICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMykpCiAgY29sbmFtZXModGVtcCkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgaHViLmFuY2hvciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCkKICAKICAKICAKbG9vcC51cCA8LSBmcmVhZChoZXJlKGNvbnNlbnN1c0RpciwgImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHlfc3RydWN0dXJlX2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKQpsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmVfZFRBR3ZzRE1TT19OT19kaWZmMC4yLmJlZHBlIikpCmFuY2hvci51cG5vIDwtIGV4dHJhY3RBbmNob3IoYmluZF9yb3dzKGxvb3AudXAsIGxvb3Aubm8pKQoKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9zdHJ1Y3R1cmVfZFRBR3ZzRE1TT19ET1dOX2RpZmYwLjIuYmVkcGUiKSkKYW5jaG9yLmRvd24gPC0gZXh0cmFjdEFuY2hvcihsb29wLmRvd24pCgogIAogIG92ZXJsYXAudXBubyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLnVwbm8sIGh1Yi5hbmNob3IpCiAgb3ZlcmxhcC5kb3duIDwtIGZpbmRPdmVybGFwcyhhbmNob3IuZG93biwgaHViLmFuY2hvcikKICAKICBuMSA8LSBsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhvdmVybGFwLnVwbm8pKSkKICBuMiA8LSBsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhvdmVybGFwLmRvd24pKSkKICAKICBwZXJjMSA8LSByb3VuZChuMS9sZW5ndGgob3ZlcmxhcC51cG5vKSoxMDAsIDIpCiAgcGVyYzIgPC0gcm91bmQobjIvbGVuZ3RoKG92ZXJsYXAuZG93bikqMTAwLCAyKQogIAogIHJlc3VsdHMgPC0gcmVzdWx0cyAlPiUgYWRkX3JvdyhpID0gaSwgdXBubyA9IHBlcmMxLCBkb3duID0gcGVyYzIpCn0KCgoKcmVzdWx0c19sb25nIDwtIHJlc3VsdHMgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHVwbm8sIGRvd24pLCBuYW1lc190byA9ICJHcm91cCIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIikKcmVzdWx0c19sb25nJEdyb3VwIDwtIGZhY3RvcihyZXN1bHRzX2xvbmckR3JvdXAsIGxldmVscyA9IGMoInVwbm8iLCAiZG93biIpKQoKIyBDcmVhdGUgdGhlIGJhciBwbG90CmdncGxvdChyZXN1bHRzX2xvbmcsIGFlcyh4ID0gZmFjdG9yKGkpLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IEdyb3VwKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiU3RydWN0dXJlIGxvb3BzIiwKICAgIHggPSAiUHJlc2VuY2Ugb2YgaHViIGFuY2hvciB3aXRoID5pIGNvbm5lY3Rpb25zIiwKICAgIHkgPSAiUGVyY2VudGFnZSIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInVwbm8iID0gImJsdWUiLCAiZG93biIgPSAicmVkIikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIHlsaW0oMCwgMTAwKQpgYGAKIyMjIyBUU1MKYGBge3J9CnJlc3VsdHMgPC0gdGliYmxlKGkgPSBudW1lcmljKCksIHBlcmMxID0gbnVtZXJpYygpLCBwZXJjMiA9IG51bWVyaWMoKSkKCmZvcihpIGluIHNlcSgxLCAxMCkpewogIGRhdGEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJEeWxhbl9odWJfZXBpc2MuY3N2IikpCiAgCiAgZGF0YS5odWIgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihhbGxfbGNvbiA+IGkpCiAgdGVtcCA8LSBkYXRhLmh1YiAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKQogIGNvbG5hbWVzKHRlbXApIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQogIGh1Yi5hbmNob3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCiAgCiAgCiAgCiAgIyMgQ2hlY2tpbmcgb3ZlcmxhcCB3aXRoIGdlbmUgVFNTCiAgdHNzIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfVFNTMi41a2IuYmVkIikpCiAgCiAgdHNzLmdyb3VwMSA8LSB0c3MgJT4lIGRwbHlyOjpmaWx0ZXIoVjYgJWluJSBncm91cDEpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCiAgY29sbmFtZXModHNzLmdyb3VwMSkgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIpCiAgdHNzLmdyb3VwMS5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodHNzLmdyb3VwMSkKICAKICB0c3MuZ3JvdXAyIDwtIHRzcyAlPiUgZHBseXI6OmZpbHRlcihWNiAlaW4lIGdyb3VwMikgJT4lIGRwbHlyOjpzZWxlY3QoVjEsIFYyLCBWMykKICBjb2xuYW1lcyh0c3MuZ3JvdXAyKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIikKICB0c3MuZ3JvdXAyLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSh0c3MuZ3JvdXAyKQogIAogIAogIG92ZXJsYXAuZ3JvdXAxIDwtIGZpbmRPdmVybGFwcyh0c3MuZ3JvdXAxLmdyLCBodWIuYW5jaG9yKQogIG92ZXJsYXAuZ3JvdXAyIDwtIGZpbmRPdmVybGFwcyh0c3MuZ3JvdXAyLmdyLCBodWIuYW5jaG9yKQogIAogIG4xIDwtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKG92ZXJsYXAuZ3JvdXAxKSkpCiAgbjIgPC0gbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHMob3ZlcmxhcC5ncm91cDIpKSkKICAKICBwZXJjMSA8LSByb3VuZChuMS9ucm93KHRzcy5ncm91cDEpKjEwMCwgMikKICBwZXJjMiA8LSByb3VuZChuMi9ucm93KHRzcy5ncm91cDIpKjEwMCwgMikKICAKICByZXN1bHRzIDwtIHJlc3VsdHMgJT4lIGFkZF9yb3coaSA9IGksIHBlcmMxID0gcGVyYzEsIHBlcmMyID0gcGVyYzIpCn0KCgoKcmVzdWx0c19sb25nIDwtIHJlc3VsdHMgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHBlcmMxLCBwZXJjMiksIG5hbWVzX3RvID0gIkdyb3VwIiwgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2UiKQoKIyBDcmVhdGUgdGhlIGJhciBwbG90CmdncGxvdChyZXN1bHRzX2xvbmcsIGFlcyh4ID0gZmFjdG9yKGkpLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IEdyb3VwKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUGVyY2VudGFnZSBieSAnaScgZm9yIHBlcmMxIGFuZCBwZXJjMiIsCiAgICB4ID0gIlByZXNlbmNlIG9mIGh1YiBhbmNob3Igd2l0aCA+aSBjb25uZWN0aW9ucyIsCiAgICB5ID0gIlBlcmNlbnRhZ2UiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJwZXJjMSIgPSAiYmx1ZSIsICJwZXJjMiIgPSAicmVkIikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCiMjI1syLjMwXSBIM0syN2FjIHBlYWsgbnVtYmVyIHBlciAxMGtiCmBgYHtyfQpwcm9jZXNzX2dyb3VwIDwtIGZ1bmN0aW9uKGdyb3VwX25hbWUsIGdlbmVfZGF0YSwgYmlucykgewogICMgRmlsdGVyIGZvciB0aGUgc3BlY2lmaWMgZ3JvdXAKICBUU1NfZ3JvdXAgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKAogICAgZ2VuZV9kYXRhICU+JSBmaWx0ZXIoZW5zZW1ibCAlaW4lIGdldChncm91cF9uYW1lKSksIAogICAga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRQogICkKICAKICAjIFByb2Nlc3MgZWFjaCBUU1MgaW4gdGhlIGdyb3VwCiAgYWxsX3Jlc3VsdHMgPC0gbWFwX2RmcihzZXFfbGVuKGxlbmd0aChUU1NfZ3JvdXApKSwgZnVuY3Rpb24oaSkgewogICAgIyBGaW5kIG92ZXJsYXBwaW5nIGJpbnMKICAgIG92ZXJsYXBwaW5nX2JpbnMgPC0gZmluZE92ZXJsYXBzKFRTU19ncm91cFtpXSwgYmlucykKICAgIGJpbnNfbmVhcl90c3MgPC0gYXNfdGliYmxlKGJpbnNbc3ViamVjdEhpdHMob3ZlcmxhcHBpbmdfYmlucyldKQogICAgCiAgICAjIENhbGN1bGF0ZSBkaXN0YW5jZSBiaW4KICAgIFRTU2NlbnRlciA8LSAoYXNfdGliYmxlKFRTU19ncm91cFtpXSkgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNlbnRlciA9IChzdGFydCArIGVuZCkgLyAyKSkkY2VudGVyCiAgICBjZW50ZXJCaW5TdGFydCA8LSBmbG9vcihUU1NjZW50ZXIgLyAxMGUzKSAqIDEwZTMgKyAxCiAgICBiaW5zX25lYXJfdHNzIDwtIGJpbnNfbmVhcl90c3MgJT4lCiAgICAgIG11dGF0ZShkaXN0YW5jZUJpbiA9IGFicygoc3RhcnQgLSBjZW50ZXJCaW5TdGFydCkpIC8gMTBlMykKICAgIAogICAgIyBTdW1tYXJpemUgcmVzdWx0cwogICAgcmVzdWx0IDwtIGJpbnNfbmVhcl90c3MgJT4lCiAgICAgIGdyb3VwX2J5KGRpc3RhbmNlQmluKSAlPiUKICAgICAgc3VtbWFyaXNlKG1lYW5fcGVha19jb3VudHMgPSBtZWFuKHBlYWtfY291bnRzLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICAgICAgbXV0YXRlKGdlbmUgPSBUU1NfZ3JvdXBbaV0kZW5zZW1ibCkKICAgIHJldHVybihyZXN1bHQpCiAgfSkKICAKICAjIENhbGN1bGF0ZSBtZWFuIGFuZCBTRCBmb3IgdGhlIGdyb3VwCiAgbWVhbl9kYXRhIDwtIGFsbF9yZXN1bHRzICU+JQogICAgZ3JvdXBfYnkoZGlzdGFuY2VCaW4pICU+JQogICAgc3VtbWFyaXNlKG1lYW5fcGVha19jb3VudHMgPSBtZWFuKG1lYW5fcGVha19jb3VudHMsIG5hLnJtID0gVFJVRSkpCiAgCiAgc2RfZGF0YSA8LSBhbGxfcmVzdWx0cyAlPiUKICAgIGdyb3VwX2J5KGRpc3RhbmNlQmluKSAlPiUKICAgIHN1bW1hcmlzZShzZF9wZWFrX2NvdW50cyA9IHNkKG1lYW5fcGVha19jb3VudHMsIG5hLnJtID0gVFJVRSkpCiAgCiAgIyBKb2luIGFuZCBhZGQgZ3JvdXAgbmFtZQogIHN1bW1hcnlfZGF0YSA8LSBsZWZ0X2pvaW4obWVhbl9kYXRhLCBzZF9kYXRhLCBieSA9ICJkaXN0YW5jZUJpbiIpICU+JQogICAgbXV0YXRlKGdyb3VwID0gZ3JvdXBfbmFtZSkKICAKICByZXR1cm4oc3VtbWFyeV9kYXRhKQp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKCiMjIEltcG9ydCBwZWFrCnJlZkRpciA8LSBoZXJlKCIuLi8uLiIsICJyZWZlcmVuY2UiKQojcGVhay5IM0syN2FjIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJHU00yNDM4NDc2X0VDLURHLTM0NTgtSDNLMjdBQ19BU1lOXzEubmFycm93UGVhay5iZWQiKSkKcGVhay5IM0syN2FjIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay5iZWQiKSkKI3BlYWsuSDNLMjdhYyA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTBfUkFEMjFfYWI5OTJfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCgojIyBJbXBvcnQgMTBrYiBiaW4KdGVtcCA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTAuYmluLjEwa2IuYmVkIikpCmNvbG5hbWVzKHRlbXApIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoc3RhcnQgPSBzdGFydCsxKQpiaW5zLjEwa2IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgojIyBDb3VudCBvdmVybGFwCmNvdW50cyA8LSBjb3VudE92ZXJsYXBzKGJpbnMuMTBrYiwgcGVhay5IM0syN2FjKQptY29scyhiaW5zLjEwa2IpJHBlYWtfY291bnRzIDwtIGNvdW50cwoKIyMgR2V0dGluZyBUU1MKZmxhbmtTaXplIDwtIDFlNgpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNikKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJlbnNlbWJsIikKCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCiNUU1MxbWIuZ3JvdXAxLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShnZW5lLnRiICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmwgJWluJSBnZW5lLmdyb3VwMSksIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCiNUU1MxbWIuZ3JvdXAyLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShnZW5lLnRiICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmwgJWluJSBnZW5lLmdyb3VwMiksIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgTGlzdCBvZiBncm91cHMgdG8gcHJvY2Vzcwpncm91cHMgPC0gYygiZ2VuZS5ncm91cDEiLCAiZ2VuZS5ncm91cDIiKQoKIyBQcm9jZXNzIGVhY2ggZ3JvdXAgYW5kIGNvbWJpbmUgcmVzdWx0cwpzdW1tYXJ5X2RhdGEgPC0gbWFwX2Rmcihncm91cHMsIH4gcHJvY2Vzc19ncm91cCgueCwgZ2VuZS50YiwgYmlucy4xMGtiKSkKCiMgQWRkIHRoZSBhZGRpdGlvbmFsIHJvd3MgZm9yIGRpc3RhbmNlQmluID0gMApzdW1tYXJ5X2RhdGEgPC0gc3VtbWFyeV9kYXRhICU+JQogIG11dGF0ZShkaXN0YW5jZUJpbiA9IGRpc3RhbmNlQmluICsgMSkgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAxIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAyIikKCiMgUGxvdCB0aGUgcmVzdWx0cwpwIDwtIGdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZGlzdGFuY2VCaW4sIHkgPSBtZWFuX3BlYWtfY291bnRzLCBjb2xvciA9IGdyb3VwKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDAuNSkgKwogIGxhYnMoCiAgICB4ID0gIkRpc3RhbmNlIGJpbiAoMTBrYikiLAogICAgeSA9ICJIM0s0bWUzIHBlYWsgY291bnQiCiAgKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsIDAuOCkgICMgTW92ZXMgbGVnZW5kIGluc2lkZSB0aGUgcGxvdCAoeCwgeSByZWxhdGl2ZSBjb29yZGluYXRlcykKICApICsKICBndWlkZXMoCiAgICBmaWxsID0gZ3VpZGVfbGVnZW5kKAogICAgICBrZXl3aWR0aCA9IDAuMiwgICMgQWRqdXN0IHRoZSB3aWR0aCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICAga2V5aGVpZ2h0ID0gMC4yICAjIEFkanVzdCB0aGUgaGVpZ2h0IG9mIHRoZSBsZWdlbmQga2V5cwogICAgKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihjKCIjNzc3Nzc3IiwgIiNGMjhFMkMiKSkpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpmaWxlTmFtZSA8LSBwYXN0ZTAoImJpblBlYWtEZW5zaXR5X1JBRDIxX2JpbmFyeUdyb3VwIikKd2lkdGggPC0gMzIqbW1Ub0luY2gKaGVpZ2h0IDwtIDM1Km1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKCmBgYHtyfQoKIyMjIyMjIyBET2luZyB0aGlzIGZvciBQLVMgZ3JvdXBzCnJlc3VsdERpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQiKQp0ZW1wMiA8LSByZWFkUkRTKGhlcmUocmVzdWx0RGlyLCAiZ2VuZV9sb29wX2xpbmsucmRzIikpCgpwc092ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gNCkpJGdlbmUKcHNPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDMsIG51bV9wcyA8IDQpKSRnZW5lCnBzT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAyLCBudW1fcHMgPCAzKSkkZ2VuZQpwc092ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMSwgbnVtX3BzIDwgMikpJGdlbmUKcHNPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzIDwgMSkpJGdlbmUKCiMgTGlzdCBvZiBncm91cHMgdG8gcHJvY2Vzcwpncm91cHMgPC0gYygicHNPdmVyMCIsICJwc092ZXIxIiwgInBzT3ZlcjIiLCAicHNPdmVyMyIsICJwc092ZXI0IikKCiMgUHJvY2VzcyBlYWNoIGdyb3VwIGFuZCBjb21iaW5lIHJlc3VsdHMKc3VtbWFyeV9kYXRhIDwtIG1hcF9kZnIoZ3JvdXBzLCB+IHByb2Nlc3NfZ3JvdXAoLngsIGdlbmUudGIsIGJpbnMuMTBrYikpCgojIEFkZCB0aGUgYWRkaXRpb25hbCByb3dzIGZvciBkaXN0YW5jZUJpbiA9IDAKc3VtbWFyeV9kYXRhIDwtIHN1bW1hcnlfZGF0YSAlPiUKICBtdXRhdGUoZGlzdGFuY2VCaW4gPSBkaXN0YW5jZUJpbiArIDEpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJwc092ZXIwIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gInBzT3ZlcjEiKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicHNPdmVyMiIpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJwc092ZXIzIiklPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicHNPdmVyNCIpCgojIFBsb3QgdGhlIHJlc3VsdHMKcCA8LSBnZ3Bsb3Qoc3VtbWFyeV9kYXRhLCBhZXMoeCA9IGRpc3RhbmNlQmluLCB5ID0gbWVhbl9wZWFrX2NvdW50cywgY29sb3IgPSBncm91cCkpICsgCiAgZ2VvbV9saW5lKHNpemUgPSAwLjUpICsKICBsYWJzKAogICAgeCA9ICJEaXN0YW5jZSBiaW4gKDEwa2IpIiwKICAgIHkgPSAiSDNLNG1lMyBwZWFrIGNvdW50IgogICkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjgpICAjIE1vdmVzIGxlZ2VuZCBpbnNpZGUgdGhlIHBsb3QgKHgsIHkgcmVsYXRpdmUgY29vcmRpbmF0ZXMpCiAgKSArCiAgZ3VpZGVzKAogICAgZmlsbCA9IGd1aWRlX2xlZ2VuZCgKICAgICAga2V5d2lkdGggPSAwLjIsICAjIEFkanVzdCB0aGUgd2lkdGggb2YgdGhlIGxlZ2VuZCBrZXlzCiAgICAgIGtleWhlaWdodCA9IDAuMiAgIyBBZGp1c3QgdGhlIGhlaWdodCBvZiB0aGUgbGVnZW5kIGtleXMKICAgICkpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkKCmZpbGVOYW1lIDwtIHBhc3RlMCgiYmluUGVha0RlbnNpdHlfUkFEMjFfcHNHcm91cDExIikKd2lkdGggPC0gMzIqbW1Ub0luY2gKaGVpZ2h0IDwtIDM1Km1tVG9JbmNoCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgojIyMgUEUKcGVPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDQpKSRnZW5lCnBlT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAzLCBudW1fcGUgPCA0KSkkZ2VuZQpwZU92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMiwgbnVtX3BlIDwgMykpJGdlbmUKcGVPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDEsIG51bV9wZSA8IDIpKSRnZW5lCnBlT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA8IDEpKSRnZW5lCgojIExpc3Qgb2YgZ3JvdXBzIHRvIHByb2Nlc3MKZ3JvdXBzIDwtIGMoInBlT3ZlcjAiLCAicGVPdmVyMSIsICJwZU92ZXIyIiwgInBlT3ZlcjMiLCAicGVPdmVyNCIpCgojIFByb2Nlc3MgZWFjaCBncm91cCBhbmQgY29tYmluZSByZXN1bHRzCnN1bW1hcnlfZGF0YSA8LSBtYXBfZGZyKGdyb3VwcywgfiBwcm9jZXNzX2dyb3VwKC54LCBnZW5lLnRiLCBiaW5zLjEwa2IpKQoKIyBBZGQgdGhlIGFkZGl0aW9uYWwgcm93cyBmb3IgZGlzdGFuY2VCaW4gPSAwCnN1bW1hcnlfZGF0YSA8LSBzdW1tYXJ5X2RhdGEgJT4lCiAgbXV0YXRlKGRpc3RhbmNlQmluID0gZGlzdGFuY2VCaW4gKyAxKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicGVPdmVyMCIpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJwZU92ZXIxIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gInBlT3ZlcjIiKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicGVPdmVyMyIpJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gInBlT3ZlcjQiKQoKIyBQbG90IHRoZSByZXN1bHRzCmdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZGlzdGFuY2VCaW4sIHkgPSBtZWFuX3BlYWtfY291bnRzLCBjb2xvciA9IGdyb3VwKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsgeGxpbSgwLCAxMCkrCiAgbGFicygKICAgIHRpdGxlID0gIk1lYW4gUGVhayBDb3VudHMiLAogICAgeCA9ICJEaXN0YW5jZSBCaW4gKDEwIGtiKSIsCiAgICB5ID0gIk1lYW4gUGVhayBDb3VudHMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKQogICkKCiMjIyMjIyMjIyMjIyMjIwpwcE92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gNCkpJGdlbmUKcHBPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDMsIG51bV9wcCA8IDQpKSRnZW5lCnBwT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAyLCBudW1fcHAgPCAzKSkkZ2VuZQpwcE92ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMSwgbnVtX3BwIDwgMikpJGdlbmUKcHBPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwIDwgMSkpJGdlbmUKCiMgTGlzdCBvZiBncm91cHMgdG8gcHJvY2Vzcwpncm91cHMgPC0gYygicHBPdmVyMCIsICJwcE92ZXIxIiwgInBwT3ZlcjIiLCAicHBPdmVyMyIsICJwcE92ZXI0IikKCiMgUHJvY2VzcyBlYWNoIGdyb3VwIGFuZCBjb21iaW5lIHJlc3VsdHMKc3VtbWFyeV9kYXRhIDwtIG1hcF9kZnIoZ3JvdXBzLCB+IHByb2Nlc3NfZ3JvdXAoLngsIGdlbmUudGIsIGJpbnMuMTBrYikpCgojIEFkZCB0aGUgYWRkaXRpb25hbCByb3dzIGZvciBkaXN0YW5jZUJpbiA9IDAKc3VtbWFyeV9kYXRhIDwtIHN1bW1hcnlfZGF0YSAlPiUKICBtdXRhdGUoZGlzdGFuY2VCaW4gPSBkaXN0YW5jZUJpbiArIDEpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJwcE92ZXIwIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gInBwT3ZlcjEiKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicHBPdmVyMiIpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJwcE92ZXIzIiklPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAicHBPdmVyNCIpCgojIFBsb3QgdGhlIHJlc3VsdHMKZ2dwbG90KHN1bW1hcnlfZGF0YSwgYWVzKHggPSBkaXN0YW5jZUJpbiwgeSA9IG1lYW5fcGVha19jb3VudHMsIGNvbG9yID0gZ3JvdXApKSArIAogIGdlb21fbGluZShzaXplID0gMSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJNZWFuIFBlYWsgQ291bnRzIiwKICAgIHggPSAiRGlzdGFuY2UgQmluICgxMCBrYikiLAogICAgeSA9ICJNZWFuIFBlYWsgQ291bnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMykKICApCmBgYAojIyMgWzIuMzFdIFRlc3RpbmcgU0VzPwpgYGB7cn0KcGVhay5XaHl0ZS5TRSA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAic3VwZXJFbmhhbmNlcl9XaHl0ZV9FU0NfbW0xMC5iZWQiKSkKcGVhay5EeWxhbi5TRSA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAic3VwZXJFbmhhbmNlcl9EeWxhbl9FU0MuYmVkIikpCgoKCmZsYW5rU2l6ZSA8LSAwLjVlNgpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNiwgVjUpCmNvbG5hbWVzKGdlbmUudGIpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiLCAiZW5zZW1ibCIsICJnZW5lIikKCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKClRTUzFtYi5ncm91cDEuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGdlbmUuZ3JvdXAxKSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRSkKVFNTMW1iLmdyb3VwMi5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZ2VuZS50YiAlPiUgZHBseXI6OmZpbHRlcihlbnNlbWJsICVpbiUgZ2VuZS5ncm91cDIpLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFKQoKCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAxLmdyLCBwZWFrLldoeXRlLlNFKSkpKS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHMoVFNTMW1iLmdyb3VwMi5nciwgcGVhay5XaHl0ZS5TRSkpKSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAxLmdyLCBwZWFrLkR5bGFuLlNFKSkpKS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHMoVFNTMW1iLmdyb3VwMi5nciwgcGVhay5EeWxhbi5TRSkpKSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCiNWaWV3KGFzX3RpYmJsZShUU1MxbWIuZ3JvdXAxLmdyW3VuaXF1ZShxdWVyeUhpdHMoZmluZE92ZXJsYXBzKFRTUzFtYi5ncm91cDEuZ3IsIHBlYWsuV2h5dGUuU0UpKSldKSkKI1ZpZXcoYXNfdGliYmxlKFRTUzFtYi5ncm91cDEuZ3JbdW5pcXVlKHF1ZXJ5SGl0cyhmaW5kT3ZlcmxhcHMoVFNTMW1iLmdyb3VwMS5nciwgcGVhay5EeWxhbi5TRSkpKV0pKQoKZ2VuZS5ncm91cDEuU0UgPC0gKGFzX3RpYmJsZShUU1MxbWIuZ3JvdXAxLmdyW3VuaXF1ZShxdWVyeUhpdHMoZmluZE92ZXJsYXBzKFRTUzFtYi5ncm91cDEuZ3IsIHBlYWsuRHlsYW4uU0UpKSldKSkkZW5zZW1ibApnZW5lLmdyb3VwMS5ub1NFIDwtIGdlbmUuZ3JvdXAxWyEoZ2VuZS5ncm91cDEgJWluJSBnZW5lLmdyb3VwMS5TRSldCgpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoVFNTMW1iLmdyb3VwMi5nciwgcGVhay5EeWxhbi5TRSkKdW5pcXVlX2hpdHMgPC0gdW5pcXVlKHF1ZXJ5SGl0cyhvdmVybGFwcykpCmdlbmUuZ3JvdXAyLlNFIDwtIGFzX3RpYmJsZShUU1MxbWIuZ3JvdXAyLmdyW3VuaXF1ZV9oaXRzXSkkZW5zZW1ibApnZW5lLmdyb3VwMi5ub1NFIDwtIGFzX3RpYmJsZShUU1MxbWIuZ3JvdXAyLmdyWy11bmlxdWVfaGl0c10pJGVuc2VtYmwKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLAogICAgICAgICAgICAgICAgVFNTc3RhcnQgPSBUU1MgLSAxZTYsCiAgICAgICAgICAgICAgICBUU1NlbmQgPSBUU1MgKyAxZTYpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIFRTU3N0YXJ0LCBUU1NlbmQsIFY2LCBWNSkKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJlbnNlbWJsIiwgImdlbmUiKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIExpc3Qgb2YgZ3JvdXBzIHRvIHByb2Nlc3MKZ3JvdXBzIDwtIGMoImdlbmUuZ3JvdXAxLlNFIiwgImdlbmUuZ3JvdXAxLm5vU0UiKQoKIyBQcm9jZXNzIGVhY2ggZ3JvdXAgYW5kIGNvbWJpbmUgcmVzdWx0cwpzdW1tYXJ5X2RhdGEgPC0gbWFwX2Rmcihncm91cHMsIH4gcHJvY2Vzc19ncm91cCgueCwgZ2VuZS50YiwgYmlucy4xMGtiKSkKCiMgQWRkIHRoZSBhZGRpdGlvbmFsIHJvd3MgZm9yIGRpc3RhbmNlQmluID0gMApzdW1tYXJ5X2RhdGEgPC0gc3VtbWFyeV9kYXRhICU+JQogIG11dGF0ZShkaXN0YW5jZUJpbiA9IGRpc3RhbmNlQmluICsgMSkgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAxLlNFIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAxLm5vU0UiKQoKIyBQbG90IHRoZSByZXN1bHRzCmdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZGlzdGFuY2VCaW4sIHkgPSBtZWFuX3BlYWtfY291bnRzLCBjb2xvciA9IGdyb3VwKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSBwYXN0ZTAoIk1lYW4gUGVhayBDb3VudHMsICstIiwgZmxhbmtTaXplLCAiYnAsIFdoeXRlIFNFIiksCiAgICB4ID0gIkRpc3RhbmNlIEJpbiAoMTAga2IpIiwKICAgIHkgPSAiTWVhbiBQZWFrIENvdW50cyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpCiAgKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIExpc3Qgb2YgZ3JvdXBzIHRvIHByb2Nlc3MKZ3JvdXBzIDwtIGMoImdlbmUuZ3JvdXAxLlNFIiwgImdlbmUuZ3JvdXAxLm5vU0UiLCAiZ2VuZS5ncm91cDIuU0UiLCAiZ2VuZS5ncm91cDIubm9TRSIpCgojIFByb2Nlc3MgZWFjaCBncm91cCBhbmQgY29tYmluZSByZXN1bHRzCnN1bW1hcnlfZGF0YSA8LSBtYXBfZGZyKGdyb3VwcywgfiBwcm9jZXNzX2dyb3VwKC54LCBnZW5lLnRiLCBiaW5zLjEwa2IpKQoKIyBBZGQgdGhlIGFkZGl0aW9uYWwgcm93cyBmb3IgZGlzdGFuY2VCaW4gPSAwCnN1bW1hcnlfZGF0YSA8LSBzdW1tYXJ5X2RhdGEgJT4lCiAgbXV0YXRlKGRpc3RhbmNlQmluID0gZGlzdGFuY2VCaW4gKyAxKSAlPiUKICAgIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJnZW5lLmdyb3VwMS5TRSIpICU+JQogIGFkZF9yb3coZGlzdGFuY2VCaW4gPSAwLCBtZWFuX3BlYWtfY291bnRzID0gMCwgc2RfcGVha19jb3VudHMgPSAwLCBncm91cCA9ICJnZW5lLmdyb3VwMS5ub1NFIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAyLlNFIikgJT4lCiAgYWRkX3JvdyhkaXN0YW5jZUJpbiA9IDAsIG1lYW5fcGVha19jb3VudHMgPSAwLCBzZF9wZWFrX2NvdW50cyA9IDAsIGdyb3VwID0gImdlbmUuZ3JvdXAyLm5vU0UiKQoKIyBQbG90IHRoZSByZXN1bHRzCmdncGxvdChzdW1tYXJ5X2RhdGEsIGFlcyh4ID0gZGlzdGFuY2VCaW4sIHkgPSBtZWFuX3BlYWtfY291bnRzLCBjb2xvciA9IGdyb3VwKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSBwYXN0ZTAoIk1lYW4gUGVhayBDb3VudHMsICstIiwgZmxhbmtTaXplLCAiYnAsIFdoeXRlIFNFIiksCiAgICB4ID0gIkRpc3RhbmNlIEJpbiAoMTAga2IpIiwKICAgIHkgPSAiTWVhbiBQZWFrIENvdW50cyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpCiAgKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgTGlzdCBvZiBncm91cHMgdG8gcHJvY2Vzcwpncm91cHMgPC0gYygiZ2VuZS5ncm91cDIuU0UiLCAiZ2VuZS5ncm91cDIubm9TRSIpCgojIFByb2Nlc3MgZWFjaCBncm91cCBhbmQgY29tYmluZSByZXN1bHRzCnN1bW1hcnlfZGF0YSA8LSBtYXBfZGZyKGdyb3VwcywgfiBwcm9jZXNzX2dyb3VwKC54LCBnZW5lLnRiLCBiaW5zLjEwa2IpKQoKIyBBZGQgdGhlIGFkZGl0aW9uYWwgcm93cyBmb3IgZGlzdGFuY2VCaW4gPSAwCnN1bW1hcnlfZGF0YSA8LSBzdW1tYXJ5X2RhdGEgJT4lCiAgbXV0YXRlKGRpc3RhbmNlQmluID0gZGlzdGFuY2VCaW4gKyAxKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAiZ2VuZS5ncm91cDIuU0UiKSAlPiUKICBhZGRfcm93KGRpc3RhbmNlQmluID0gMCwgbWVhbl9wZWFrX2NvdW50cyA9IDAsIHNkX3BlYWtfY291bnRzID0gMCwgZ3JvdXAgPSAiZ2VuZS5ncm91cDIubm9TRSIpCgojIFBsb3QgdGhlIHJlc3VsdHMKZ2dwbG90KHN1bW1hcnlfZGF0YSwgYWVzKHggPSBkaXN0YW5jZUJpbiwgeSA9IG1lYW5fcGVha19jb3VudHMsIGNvbG9yID0gZ3JvdXApKSArIAogIGdlb21fbGluZShzaXplID0gMSkgKwogIGxhYnMoCiAgICB0aXRsZSA9IHBhc3RlMCgiTWVhbiBQZWFrIENvdW50cywgKy0iLCBmbGFua1NpemUsICJicCwgV2h5dGUgU0UiKSwKICAgIHggPSAiRGlzdGFuY2UgQmluICgxMCBrYikiLAogICAgeSA9ICJNZWFuIFBlYWsgQ291bnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMykKICApCgojIyBDaGVja2luZyBQLVMgaW4gdGhlIHN1YnNldCBvZiBnZW5lcwoKcmVzdWx0RGlyIDwtIGhlcmUoIi4uLy4uL3Jlc3VsdCIpCnRlbXAyIDwtIHJlYWRSRFMoaGVyZShyZXN1bHREaXIsICJnZW5lX2xvb3BfbGluay5yZHMiKSkKCnRlbXAzIDwtIHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmUgJWluJSBjKGdlbmUuZ3JvdXAxKSkgJT4lCiAgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbihnZW5lICVpbiUgZ2VuZS5ncm91cDEuU0UgfiAiU0UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJub1NFIikpCgoKZ2dwbG90KHRlbXAzLCBhZXMoeCA9IGdyb3VwLCB5ID0gbnVtX3BzKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGdyb3VwKSkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEpICsgdGhlbWVfY2xhc3NpYygpCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkbnVtX3BwCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJG51bV9wcAogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCgpnZXRQdmFsV2lsY294KHRlbXAzLCAibm9TRSIsICJTRSIpCmBgYAoKIyMjIFsyLjMyXSBDaGVja2luZyBkaXJlY3Rpb25hbGl0eQpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYpJT4lIAogIGRwbHlyOjptdXRhdGUoZGlzdGFuY2UgPSBzdGFydDIgLSBzdGFydDEpCgoKZ2VuZUFubm9EYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgdW5uZXN0KGdlbmUpCgoKZ2VuZS50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMykpICU+JQogIGRwbHlyOjpzZWxlY3QoVjYsIFRTUykKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiZW5zZW1ibCIsICJUU1MiKQoKCmdlbmVBbm5vRGF0YSAgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKGdlbmUudGIsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibCIpKQoKZGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2LCAyOSwgMzEsIDM1KSkgJT4lCiAgcm93d2lzZSgpICU+JQogIGRwbHlyOjptdXRhdGUoZGlzdFRvQW5jaG9yMSA9IChzdGFydDEgKyBlbmQxKS8yIC0gVFNTLAogICAgICAgICAgICAgICAgZGlzdFRvQW5jaG9yMiA9IChzdGFydDIgKyBlbmQyKS8yIC0gVFNTLAogICAgICAgICAgICAgICAgZGlzdFRvQW5jaG9yID0gaWZfZWxzZShhYnMoZGlzdFRvQW5jaG9yMSkgPiBhYnMoZGlzdFRvQW5jaG9yMiksIGRpc3RUb0FuY2hvcjEsIGRpc3RUb0FuY2hvcjIpLAogICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gaWZfZWxzZShkaXN0VG9BbmNob3IgPiAwLCAicmlnaHQiLCAibGVmdCIpKQoKZGF0YS5kaXJlY3Rpb25hbGl0eSA8LSBkYXRhICU+JSBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCksCiAgICAgICAgICAgIG5fcmlnaHQgPSBzdW0oZGlyZWN0aW9uID09ICJyaWdodCIpLAogICAgICAgICAgICBuX2xlZnQgPSBzdW0oZGlyZWN0aW9uID09ICJsZWZ0IikpICU+JQogIGRwbHlyOjpmaWx0ZXIoY291bnQgPiAxKSAlPiUKICBkcGx5cjo6bXV0YXRlKG4gPSBuX3JpZ2h0ICsgbl9sZWZ0LAogICAgICAgICAgICAgICAgZGlyZWN0aW9uYWxpdHkgPSBhYnMoKG5fcmlnaHQgLSBuX2xlZnQpL24pKQoKCiNnZ3Bsb3QoZGF0YS5kaXJlY3Rpb25hbGl0eSwgYWVzKHggPSBkaXJlY3Rpb25hbGl0eSkpICsgZ2VvbV9oaXN0b2dyYW0oKSArIHRoZW1lX2NsYXNzaWMoKQoKCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCnRlbXAgPC0gZGF0YS5kaXJlY3Rpb25hbGl0eSAlPiUgZHBseXI6OmZpbHRlcihnZW5lICVpbiUgYyhnZW5lLmdyb3VwMSwgZ2VuZS5ncm91cDIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gaWZfZWxzZShnZW5lICVpbiUgZ2VuZS5ncm91cDEsICJncm91cDEiLCAiZ3JvdXAyIikpCgoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaXJlY3Rpb25hbGl0eSkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUoIlAtUyIpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNQUwoKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGRpcmVjdGlvbmFsaXR5CiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJGRpcmVjdGlvbmFsaXR5CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKCnJlc3VsdERpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQiKQp0ZW1wMiA8LSByZWFkUkRTKGhlcmUocmVzdWx0RGlyLCAiZ2VuZV9sb29wX2xpbmsucmRzIikpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAzLCBudW1fcHMgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMiwgbnVtX3BzIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDEsIG51bV9wcyA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA8IDEpKSRnZW5lCgp0ZW1wIDwtIGRhdGEuZGlyZWN0aW9uYWxpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZSAlaW4lIGMocHNPdmVyMCwgcHNPdmVyMSwgcHNPdmVyMiwgcHNPdmVyMywgcHNPdmVyNCkpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oZ2VuZSAlaW4lIHBzT3ZlcjAgfiAicHNPdmVyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHNPdmVyMSB+ICJwc092ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwc092ZXIyIH4gInBzT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBzT3ZlcjMgfiAicHNPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHNPdmVyNCB+ICJwc092ZXI0IikpCgpwMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMyIsICJwc092ZXI0IiksIDUpCnAyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIyIiwgInBzT3ZlcjMiKSwgNSkKcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBzT3ZlcjEiLCAicHNPdmVyMiIpLCA1KQpwMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHNPdmVyMCIsICJwc092ZXIxIiksIDUpCnAwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwc092ZXIwIiwgInBzT3ZlcjQiKSwgNSkKCgoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaXJlY3Rpb25hbGl0eSkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUoIlAtTiIpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInAzNDogIiwgY29udlB2YWx1ZShwMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDIzOiAiLCBjb252UHZhbHVlKHAyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAwMTogIiwgY29udlB2YWx1ZShwMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDA0OiAiLCBjb252UHZhbHVlKHAwNCksICJcbiIpLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyBwZQoKcGVPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDQpKSRnZW5lCnBlT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAzLCBudW1fcGUgPCA0KSkkZ2VuZQpwZU92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMiwgbnVtX3BlIDwgMykpJGdlbmUKcGVPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDEsIG51bV9wZSA8IDIpKSRnZW5lCnBlT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA8IDEpKSRnZW5lCgp0ZW1wIDwtIGRhdGEuZGlyZWN0aW9uYWxpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZSAlaW4lIGMocGVPdmVyMCwgcGVPdmVyMSwgcGVPdmVyMiwgcGVPdmVyMywgcGVPdmVyNCkpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oZ2VuZSAlaW4lIHBlT3ZlcjAgfiAicGVPdmVyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcGVPdmVyMSB+ICJwZU92ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwZU92ZXIyIH4gInBlT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBlT3ZlcjMgfiAicGVPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcGVPdmVyNCB+ICJwZU92ZXI0IikpCgpwMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVPdmVyMyIsICJwZU92ZXI0IiksIDUpCnAyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwZU92ZXIyIiwgInBlT3ZlcjMiKSwgNSkKcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBlT3ZlcjEiLCAicGVPdmVyMiIpLCA1KQpwMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVPdmVyMCIsICJwZU92ZXIxIiksIDUpCnAwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwZU92ZXIwIiwgInBlT3ZlcjQiKSwgNSkKCgoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaXJlY3Rpb25hbGl0eSkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUoIlAtTiIpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInAzNDogIiwgY29udlB2YWx1ZShwMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDIzOiAiLCBjb252UHZhbHVlKHAyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAwMTogIiwgY29udlB2YWx1ZShwMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDA0OiAiLCBjb252UHZhbHVlKHAwNCksICJcbiIpLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyBwcAoKcHBPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDQpKSRnZW5lCnBwT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAzLCBudW1fcHAgPCA0KSkkZ2VuZQpwcE92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMiwgbnVtX3BwIDwgMykpJGdlbmUKcHBPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDEsIG51bV9wcCA8IDIpKSRnZW5lCnBwT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA8IDEpKSRnZW5lCgp0ZW1wIDwtIGRhdGEuZGlyZWN0aW9uYWxpdHkgJT4lIGRwbHlyOjpmaWx0ZXIoZ2VuZSAlaW4lIGMocHBPdmVyMCwgcHBPdmVyMSwgcHBPdmVyMiwgcHBPdmVyMywgcHBPdmVyNCkpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oZ2VuZSAlaW4lIHBwT3ZlcjAgfiAicHBPdmVyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyMSB+ICJwcE92ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwcE92ZXIyIH4gInBwT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBwT3ZlcjMgfiAicHBPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyNCB+ICJwcE92ZXI0IikpCgpwMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHBPdmVyMyIsICJwcE92ZXI0IiksIDUpCnAyMyA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwcE92ZXIyIiwgInBwT3ZlcjMiKSwgNSkKcDEyIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBwT3ZlcjEiLCAicHBPdmVyMiIpLCA1KQpwMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicHBPdmVyMCIsICJwcE92ZXIxIiksIDUpCnAwNCA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwcE92ZXIwIiwgInBwT3ZlcjQiKSwgNSkKCgoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaXJlY3Rpb25hbGl0eSkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUoIlAtTiIpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNSwgbGFiZWwgPSBwYXN0ZTAoInAzNDogIiwgY29udlB2YWx1ZShwMzQpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDIzOiAiLCBjb252UHZhbHVlKHAyMyksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInAwMTogIiwgY29udlB2YWx1ZShwMDEpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicDA0OiAiLCBjb252UHZhbHVlKHAwNCksICJcbiIpLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgaGp1c3QgPSAwLCBzaXplID0gMykKCgpgYGAKCiMjIyBbMi4zM10gQ2hlY2tpbmcgZ3VpZGFuY2UKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKQoKZ2VuZUFubm9EYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgdW5uZXN0KGdlbmUpCgpnZW5lLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSkgJT4lCiAgZHBseXI6OnNlbGVjdChWNiwgVFNTKQpjb2xuYW1lcyhnZW5lLnRiKSA8LSBjKCJlbnNlbWJsIiwgIlRTUyIpCgoKZ2VuZUFubm9EYXRhICA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oZ2VuZS50YiwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsIikpCgpkYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMsIDQsIDUsIDYsIDI5LCAzMSwgMzUpKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgZHBseXI6Om11dGF0ZShkaXN0VG9BbmNob3IxID0gKHN0YXJ0MSArIGVuZDEpLzIgLSBUU1MsCiAgICAgICAgICAgICAgICBkaXN0VG9BbmNob3IyID0gKHN0YXJ0MiArIGVuZDIpLzIgLSBUU1MsCiAgICAgICAgICAgICAgICBkaXN0VG9BbmNob3IgPSBpZl9lbHNlKGFicyhkaXN0VG9BbmNob3IxKSA+IGFicyhkaXN0VG9BbmNob3IyKSwgZGlzdFRvQW5jaG9yMSwgZGlzdFRvQW5jaG9yMiksCiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSBpZl9lbHNlKGRpc3RUb0FuY2hvciA+IDAsICJyaWdodCIsICJsZWZ0IikpCgoKcmVzdWx0IDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoZ2VuZSwgZGlyZWN0aW9uKSAlPiUKICBtdXRhdGUoZGlzdFRvQW5jaG9yID0gYWJzKGRpc3RUb0FuY2hvcikpICU+JQogIG11dGF0ZShtYXhfZGlzdF9QX1MgPSBpZmVsc2UoYW55KEFubm8yID09ICJQLVMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoZGlzdFRvQW5jaG9yW0Fubm8yID09ICJQLVMiXSwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSkpICU+JQogIG11dGF0ZShpc19zbWFsbGVyID0gaWZlbHNlKGlzLm5hKG1heF9kaXN0X1BfUyksIE5BLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlzdFRvQW5jaG9yID09IG1heF9kaXN0X1BfUywgTkEsIGRpc3RUb0FuY2hvciA8IG1heF9kaXN0X1BfUykpKSAlPiUKICB1bmdyb3VwKCkKCgoKcmVzdWx0MiA8LSByZXN1bHQgJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGlzX3NtYWxsZXIpKQoKcmVzdWx0MyA8LSByZXN1bHQyICU+JSBncm91cF9ieShnZW5lLCBkaXJlY3Rpb24pICU+JQogIHN1bW1hcml6ZShjb3VudF90cnVlID0gc3VtKGlzX3NtYWxsZXIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGNvdW50X2ZhbHNlID0gc3VtKGlzX3NtYWxsZXIgPT0gRkFMU0UsIG5hLnJtID0gVFJVRSkpICU+JQogIGRwbHlyOjptdXRhdGUoY291bnQgPSBjb3VudF90cnVlICsgY291bnRfZmFsc2UsCiAgICAgICAgICAgICAgICBwZXJjID0gY291bnRfdHJ1ZS9jb3VudCoxMDApICU+JQogIGRwbHlyOjpzZWxlY3QoZ2VuZSwgZGlyZWN0aW9uLCBwZXJjKQoKcmVzdWx0MyA8LSByZXN1bHQzICU+JSBncm91cF9ieShnZW5lKSAlPiUgc3VtbWFyaXplKHBlcmMgPSBtZWFuKHBlcmMpKQoKIyMjIyMjIyBET2luZyB0aGlzIGZvciBQLVMgZ3JvdXBzCnJlc3VsdERpciA8LSBoZXJlKCIuLi8uLi9yZXN1bHQiKQp0ZW1wMiA8LSByZWFkUkRTKGhlcmUocmVzdWx0RGlyLCAiZ2VuZV9sb29wX2xpbmsucmRzIikpCgpwc092ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gNCkpJGdlbmUKcHNPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDMsIG51bV9wcyA8IDQpKSRnZW5lCnBzT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAyLCBudW1fcHMgPCAzKSkkZ2VuZQpwc092ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMSwgbnVtX3BzIDwgMikpJGdlbmUKcHNPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzIDwgMSkpJGdlbmUKCgpyZXN1bHQ0IDwtIHJlc3VsdDMgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oZ2VuZSAlaW4lIHBzT3ZlcjAgfiAicHNPdmVyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBzT3ZlcjEgfiAicHNPdmVyMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBzT3ZlcjIgfiAicHNPdmVyMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBzT3ZlcjMgfiAicHNPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBzT3ZlcjQgfiAicHNPdmVyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BKSkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKCmdncGxvdChyZXN1bHQ0LCBhZXMoeCA9ICBncm91cCwgeSA9IHBlcmMpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArIHRoZW1lX2NsYXNzaWMoKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikKCiMjIyMjIyMgRE9pbmcgdGhpcyBmb3IgUC1FIGdyb3VwcwpwZU92ZXI0IDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gNCkpJGdlbmUKcGVPdmVyMyA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDMsIG51bV9wZSA8IDQpKSRnZW5lCnBlT3ZlcjIgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAyLCBudW1fcGUgPCAzKSkkZ2VuZQpwZU92ZXIxIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMSwgbnVtX3BlIDwgMikpJGdlbmUKcGVPdmVyMCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlIDwgMSkpJGdlbmUKCgpyZXN1bHQ0IDwtIHJlc3VsdDMgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oZ2VuZSAlaW4lIHBlT3ZlcjAgfiAicGVPdmVyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBlT3ZlcjEgfiAicGVPdmVyMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBlT3ZlcjIgfiAicGVPdmVyMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBlT3ZlcjMgfiAicGVPdmVyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSAlaW4lIHBlT3ZlcjQgfiAicGVPdmVyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BKSkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKCmdncGxvdChyZXN1bHQ0LCBhZXMoeCA9ICBncm91cCwgeSA9IHBlcmMpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArIHRoZW1lX2NsYXNzaWMoKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikKCiMjIyMjIyMgRE9pbmcgdGhpcyBmb3IgUC1QIGdyb3VwcwoKcHBPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDQpKSRnZW5lCnBwT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAzLCBudW1fcHAgPCA0KSkkZ2VuZQpwcE92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMiwgbnVtX3BwIDwgMykpJGdlbmUKcHBPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDEsIG51bV9wcCA8IDIpKSRnZW5lCnBwT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA8IDEpKSRnZW5lCgoKcmVzdWx0NCA8LSByZXN1bHQzICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKGdlbmUgJWluJSBwcE92ZXIwIH4gInBwT3ZlcjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwcE92ZXIxIH4gInBwT3ZlcjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwcE92ZXIyIH4gInBwT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwcE92ZXIzIH4gInBwT3ZlcjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwcE92ZXI0IH4gInBwT3ZlcjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgpnZ3Bsb3QocmVzdWx0NCwgYWVzKHggPSAgZ3JvdXAsIHkgPSBwZXJjKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpCgoKYGBgCgpgYGB7cn0KCnJlc3VsdCA8LSBkYXRhICU+JQogIGdyb3VwX2J5KGdlbmUsIGRpcmVjdGlvbikgJT4lCiAgbXV0YXRlKGRpc3RUb0FuY2hvciA9IGFicyhkaXN0VG9BbmNob3IpKSAlPiUKICBtdXRhdGUobWF4X2Rpc3RfUF9TID0gaWZlbHNlKGFueShBbm5vMiA9PSAiUC1TIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KGRpc3RUb0FuY2hvcltBbm5vMiA9PSAiUC1TIl0sIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEpKQpyZXN1bHQgPC0gcmVzdWx0ICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICE9ICJQLVMiKSAlPiUKICBtdXRhdGUoaXNfc21hbGxlciA9IGlmZWxzZShpcy5uYShtYXhfZGlzdF9QX1MpLCBOQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpc3RUb0FuY2hvciA9PSBtYXhfZGlzdF9QX1MsIE5BLCBkaXN0VG9BbmNob3IgPCBtYXhfZGlzdF9QX1MpKSkgJT4lCiAgdW5ncm91cCgpCgoKCnJlc3VsdDIgPC0gcmVzdWx0ICU+JSBkcGx5cjo6ZmlsdGVyKCFpcy5uYShpc19zbWFsbGVyKSkKCnJlc3VsdDMgPC0gcmVzdWx0MiAlPiUgZ3JvdXBfYnkoZ2VuZSwgZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpemUoY291bnRfdHJ1ZSA9IHN1bShpc19zbWFsbGVyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBjb3VudF9mYWxzZSA9IHN1bShpc19zbWFsbGVyID09IEZBTFNFLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGNvdW50ID0gY291bnRfdHJ1ZSArIGNvdW50X2ZhbHNlLAogICAgICAgICAgICAgICAgcGVyYyA9IGNvdW50X3RydWUvY291bnQqMTAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdlbmUsIGRpcmVjdGlvbiwgcGVyYykKCnJlc3VsdDMgPC0gcmVzdWx0MyAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lIHN1bW1hcml6ZShwZXJjID0gbWVhbihwZXJjKSkKCiMjIyMjIyMgRE9pbmcgdGhpcyBmb3IgUC1TIGdyb3VwcwpyZXN1bHREaXIgPC0gaGVyZSgiLi4vLi4vcmVzdWx0IikKdGVtcDIgPC0gcmVhZFJEUyhoZXJlKHJlc3VsdERpciwgImdlbmVfbG9vcF9saW5rLnJkcyIpKQoKcHNPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDQpKSRnZW5lCnBzT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA+PSAzLCBudW1fcHMgPCA0KSkkZ2VuZQpwc092ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHMgPj0gMiwgbnVtX3BzIDwgMykpJGdlbmUKcHNPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BzID49IDEsIG51bV9wcyA8IDIpKSRnZW5lCnBzT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcyA8IDEpKSRnZW5lCgoKcmVzdWx0NCA8LSByZXN1bHQzICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKGdlbmUgJWluJSBwc092ZXIwIH4gInBzT3ZlcjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwc092ZXIxIH4gInBzT3ZlcjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwc092ZXIyIH4gInBzT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwc092ZXIzIH4gInBzT3ZlcjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwc092ZXI0IH4gInBzT3ZlcjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgpnZ3Bsb3QocmVzdWx0NCwgYWVzKHggPSAgZ3JvdXAsIHkgPSBwZXJjKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpCgojIyMjIyMjIERPaW5nIHRoaXMgZm9yIFAtRSBncm91cHMKcGVPdmVyNCA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDQpKSRnZW5lCnBlT3ZlcjMgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA+PSAzLCBudW1fcGUgPCA0KSkkZ2VuZQpwZU92ZXIyIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcGUgPj0gMiwgbnVtX3BlIDwgMykpJGdlbmUKcGVPdmVyMSA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BlID49IDEsIG51bV9wZSA8IDIpKSRnZW5lCnBlT3ZlcjAgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wZSA8IDEpKSRnZW5lCgoKcmVzdWx0NCA8LSByZXN1bHQzICU+JSBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKGdlbmUgJWluJSBwZU92ZXIwIH4gInBlT3ZlcjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwZU92ZXIxIH4gInBlT3ZlcjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwZU92ZXIyIH4gInBlT3ZlcjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwZU92ZXIzIH4gInBlT3ZlcjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgJWluJSBwZU92ZXI0IH4gInBlT3ZlcjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCgpnZ3Bsb3QocmVzdWx0NCwgYWVzKHggPSAgZ3JvdXAsIHkgPSBwZXJjKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpCgojIyMjIyMjIERPaW5nIHRoaXMgZm9yIFAtUCBncm91cHMKCnBwT3ZlcjQgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSA0KSkkZ2VuZQpwcE92ZXIzIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPj0gMywgbnVtX3BwIDwgNCkpJGdlbmUKcHBPdmVyMiA8LSAodGVtcDIgJT4lIGRwbHlyOjpmaWx0ZXIobnVtX3BwID49IDIsIG51bV9wcCA8IDMpKSRnZW5lCnBwT3ZlcjEgPC0gKHRlbXAyICU+JSBkcGx5cjo6ZmlsdGVyKG51bV9wcCA+PSAxLCBudW1fcHAgPCAyKSkkZ2VuZQpwcE92ZXIwIDwtICh0ZW1wMiAlPiUgZHBseXI6OmZpbHRlcihudW1fcHAgPCAxKSkkZ2VuZQoKCnJlc3VsdDQgPC0gcmVzdWx0MyAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbihnZW5lICVpbiUgcHBPdmVyMCB+ICJwcE92ZXIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyMSB+ICJwcE92ZXIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyMiB+ICJwcE92ZXIyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyMyB+ICJwcE92ZXIzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcHBPdmVyNCB+ICJwcE92ZXI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkEpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpCgoKZ2dwbG90KHJlc3VsdDQsIGFlcyh4ID0gIGdyb3VwLCB5ID0gcGVyYykpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDUpICsgdGhlbWVfY2xhc3NpYygpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKQoKYGBgCgojIyMgWzIuMzRdIENoZWNraW5nIENUQ0YgbW90aWYgb3JpZW50YXRpb24KIyMjIyBDYWxjdWxhdGluZyBDVENGIG1vdGlmCmBgYHtyfQpwZWFrLkNUQ0YgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjQ4X0NUQ0ZfMDctNzI5X0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQoKbGlicmFyeShCU2dlbm9tZS5NbXVzY3VsdXMuVUNTQy5tbTEwKQoKIyBFeHRyYWN0IHNlcXVlbmNlcwpzZXF1ZW5jZXMgPC0gZ2V0U2VxKEJTZ2Vub21lLk1tdXNjdWx1cy5VQ1NDLm1tMTAsIHBlYWsuQ1RDRikKCgojIEdldCB0aGUgQ1RDRiBtb3RpZiAob3IgcHJvdmlkZSB5b3VyIG93biBQV00pCmN0Y2ZfbW90aWYgPC0gcXVlcnkoTW90aWZEYiwgYygiQ1RDRiIsICJNbXVzY3VsdXMiKSlbWzFdXQoKIyBTY2FuIGZvciB0aGUgbW90aWYKbW90aWZfaGl0cyA8LSBsYXBwbHkoc2VxdWVuY2VzLCBmdW5jdGlvbihzZXEpIHsKICAgIG1hdGNoUFdNKGN0Y2ZfbW90aWYsIHNlcSwgbWluLnNjb3JlID0gIjgwJSIpICMgQWRqdXN0IG1pbi5zY29yZSBhcyBuZWVkZWQKfSkKCm1vdGlmX2hpdHNfcmV2ZXJzZSA8LSBsYXBwbHkoc2VxdWVuY2VzLCBmdW5jdGlvbihzZXEpIHsKICAgIG1hdGNoUFdNKGN0Y2ZfbW90aWYsIHJldmVyc2VDb21wbGVtZW50KHNlcSksIG1pbi5zY29yZSA9ICI4MCUiKQp9KQoKIyBDb21iaW5lIHJlc3VsdHMKcmVzdWx0IDwtIG1hcHBseShmdW5jdGlvbihmd2QsIHJldikgewogICAgbGlzdChmb3J3YXJkID0gZndkLCByZXZlcnNlID0gcmV2KQp9LCBtb3RpZl9oaXRzLCBtb3RpZl9oaXRzX3JldmVyc2UsIFNJTVBMSUZZID0gRkFMU0UpCgoKcmVzdWx0W1s1XV0KCgpyZXN1bHRfdGliYmxlIDwtIHRpYmJsZSgKICAgIHBlYWtfaWQgPSBzZXFfYWxvbmcocmVzdWx0KSwgIyBDcmVhdGUgYW4gaWRlbnRpZmllciBmb3IgZWFjaCBwZWFrCiAgICBhbGlnbm1lbnQgPSBtYXBfY2hyKHJlc3VsdCwgZnVuY3Rpb24ocmVzKSB7CiAgICAgICAgaGFzX2Z3ZCA8LSBsZW5ndGgocmVzJGZvcndhcmQpID4gMAogICAgICAgIGhhc19yZXYgPC0gbGVuZ3RoKHJlcyRyZXZlcnNlKSA+IDAKICAgICAgICAKICAgICAgICBpZiAoaGFzX2Z3ZCAmJiBoYXNfcmV2KSAiZndkcmV2IgogICAgICAgIGVsc2UgaWYgKGhhc19md2QpICJmd2QiCiAgICAgICAgZWxzZSBpZiAoaGFzX3JldikgInJldiIKICAgICAgICBlbHNlICJub25lIgogICAgfSkKKQoKdGVtcCA8LSBhc190aWJibGUocGVhay5DVENGKSAlPiUgYmluZF9jb2xzKHJlc3VsdF90aWJibGUpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2VxbmFtZXMsIHN0YXJ0LCBlbmQsIGFsaWdubWVudCkKCmZ3cml0ZSh0ZW1wLCBoZXJlKHJlZkRpciwgIjMzMjQ4X0NUQ0ZfMDctNzI5X0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLm1vdGlmQW5ub3RhdGVkLmJlZCIpLCBjb2wubmFtZXMgPSBGQUxTRSwgc2VwID0gIlx0IikKYGBgCiMjIyMgQ29tcGFyaW5nIGl0IHRvIFRTUwpgYGB7cn0KY3RjZi5wZWFrIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsubW90aWZBbm5vdGF0ZWQuYmVkIikpCmNvbG5hbWVzKGN0Y2YucGVhaykgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJtb3RpZiIpCmN0Y2YucGVhay5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoY3RjZi5wZWFrLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFKQoKCmZsYW5rU2l6ZSA8LSAxCmdlbmUuVFNTLnRiIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAibW0xMF9HUkNtMzgucDZfZ2VuZV9zb3J0ZWQuYmVkIikpICU+JQogIGRwbHlyOjptdXRhdGUoVFNTID0gaWZlbHNlKFY0ID09ICIrIiwgVjIsIFYzKSwKICAgICAgICAgICAgICAgIFRTU3N0YXJ0ID0gVFNTIC0gZmxhbmtTaXplLAogICAgICAgICAgICAgICAgVFNTZW5kID0gVFNTICsgZmxhbmtTaXplKSAlPiUKICBkcGx5cjo6c2VsZWN0KFYxLCBUU1NzdGFydCwgVFNTZW5kLCBWNCwgVjUsIFY2KQpjb2xuYW1lcyhnZW5lLlRTUy50YikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJzdHJhbmQiLCAiZ2VuZSIsICJlbnNlbWJsIikKCnRzcy5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZ2VuZS5UU1MudGIsIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCgpmd2RfcGVha3MgPC0gY3RjZi5wZWFrLmdyW2N0Y2YucGVhay5nciRtb3RpZiAlaW4lIGMoImZ3ZCIsICJmd2RyZXYiKV0KcmV2X3BlYWtzIDwtIGN0Y2YucGVhay5ncltjdGNmLnBlYWsuZ3IkbW90aWYgJWluJSBjKCJyZXYiLCAiZndkcmV2IildCgojIEZpbmQgY29udmVyZ2VudCBDVENGIHBhaXJzIGZvciBlYWNoIFRTUwpjb252ZXJnZW50X3BhaXJzIDwtIGxhcHBseShzZXFfYWxvbmcodHNzLmdyKSwgZnVuY3Rpb24oaSkgewogICAgY3VycmVudF90c3MgPC0gdHNzLmdyW2ldCiAgICAKICAgICMgRmlsdGVyIHBlYWtzIG9uIHRoZSBzYW1lIGNocm9tb3NvbWUgYXMgdGhlIFRTUwogICAgZndkX3BlYWtzX2NociA8LSBmd2RfcGVha3NbYXMuY2hhcmFjdGVyKHNlcW5hbWVzKGZ3ZF9wZWFrcykpID09IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhjdXJyZW50X3RzcykpXQogICAgcmV2X3BlYWtzX2NociA8LSByZXZfcGVha3NbYXMuY2hhcmFjdGVyKHNlcW5hbWVzKHJldl9wZWFrcykpID09IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhjdXJyZW50X3RzcykpXQogICAgCiAgICAjIEZpbmQgdGhlIGNsb3Nlc3QgZm9yd2FyZCBwZWFrIHRvIHRoZSBsZWZ0IG9mIHRoZSBUU1MKICAgIGxlZnRfZndkIDwtIGZ3ZF9wZWFrc19jaHJbc3RhcnQoZndkX3BlYWtzX2NocikgPCBzdGFydChjdXJyZW50X3RzcyldCiAgICBjbG9zZXN0X2Z3ZCA8LSBpZiAobGVuZ3RoKGxlZnRfZndkKSA+IDApIHsKICAgICAgbGVmdF9md2Rbd2hpY2gubWF4KHN0YXJ0KGxlZnRfZndkKSldCiAgICB9IGVsc2UgewogICAgICBOQQogICAgfQogICAgCiAgICAjIEZpbmQgdGhlIGNsb3Nlc3QgcmV2ZXJzZSBwZWFrIHRvIHRoZSByaWdodCBvZiB0aGUgVFNTCiAgICByaWdodF9yZXYgPC0gcmV2X3BlYWtzX2NocltzdGFydChyZXZfcGVha3NfY2hyKSA+IHN0YXJ0KGN1cnJlbnRfdHNzKV0KICAgIGNsb3Nlc3RfcmV2IDwtIGlmIChsZW5ndGgocmlnaHRfcmV2KSA+IDApIHsKICAgICAgcmlnaHRfcmV2W3doaWNoLm1pbihzdGFydChyaWdodF9yZXYpKV0KICAgIH0gZWxzZSB7CiAgICAgIE5BCiAgICB9CiAgICAKICAgICMgQ29tYmluZSByZXN1bHRzIGlmIGJvdGggY2xvc2VzdCBwZWFrcyBleGlzdAogICAgaWYgKCFpcy5uYShjbG9zZXN0X2Z3ZCkgJiYgIWlzLm5hKGNsb3Nlc3RfcmV2KSkgewogICAgICAgIHRpYmJsZSgKICAgICAgICAgIGNocm9tMSA9IGFzLmNoYXJhY3RlcihzZXFuYW1lcyhjbG9zZXN0X2Z3ZCkpLAogICAgICAgICAgc3RhcnQxID0gc3RhcnQoY2xvc2VzdF9md2QpLAogICAgICAgICAgZW5kMSA9IGVuZChjbG9zZXN0X2Z3ZCksCiAgICAgICAgICBjaHJvbTIgPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoY2xvc2VzdF9yZXYpKSwKICAgICAgICAgIHN0YXJ0MiA9IHN0YXJ0KGNsb3Nlc3RfcmV2KSwKICAgICAgICAgIGVuZDIgPSBlbmQoY2xvc2VzdF9yZXYpLAogICAgICAgICAgZW5zZW1ibCA9IGN1cnJlbnRfdHNzJGVuc2VtYmwsCiAgICAgICAgKQogICAgfSBlbHNlIHsKICAgICAgICBOVUxMCiAgICB9Cn0pCgojIENvbWJpbmUgcmVzdWx0cyBpbnRvIGEgdGliYmxlCnJlc3VsdF90aWJibGUgPC0gYmluZF9yb3dzKGNvbnZlcmdlbnRfcGFpcnMpCgpmd3JpdGUocmVzdWx0X3RpYmJsZSwgaGVyZShyZWZEaXIsICJ0c3NfY29udmVyZ2VudF9jdGNmX21vdGlmX3BhaXJzLmJlZHBlIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQpmd3JpdGUoZ2VuZS5UU1MudGIgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA1KSksIGhlcmUocmVmRGlyLCAidHNzXzJicC5iZWQiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCgp0ZW1wIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAidHNzX2NvbnZlcmdlbnRfY3RjZl9tb3RpZl9wYWlycy5iZWRwZSIpKSAlPiUgZHBseXI6OmZpbHRlcihWNyA9PSAiS2xmNCIpCgpmd3JpdGUoYXNfdGliYmxlKHRlbXApLCBoZXJlKHJlZkRpciwgInRzc19jb252ZXJnZW50X2N0Y2ZfbW90aWZfcGFpcnNfa2xmNC5iZWRwZSIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKCiMgQ2hlY2tpbmcgc2l6ZSBkaXN0cmlidXRpb24gb2YgY3RjZiBwYWlyCnRlbXAgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJ0c3NfY29udmVyZ2VudF9jdGNmX21vdGlmX3BhaXJzLmJlZHBlIikpCnRlbXAgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShzaXplID0gKFY2ICsgVjUpLzIgLSAoVjMgKyBWMikvMiwKICAgICAgICAgICAgICAgICAgICAgICBpZCA9IHBhc3RlKFYxLCBWMiwgVjMsIFY1LCBWNiwgc2VwID0gIl8iKSkKdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6c2VsZWN0KGlkLCBzaXplKSAlPiUgZGlzdGluY3QoKQoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gc2l6ZSkpICsgZ2VvbV9oaXN0b2dyYW0oKSArIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYiwgbGltaXRzID0gYygwLCAxZTYpKSArIHNjYWxlX3lfbG9nMTAoKSArIHRoZW1lX2NsYXNzaWMoKSArIGdndGl0bGUoInNpemUgZGlzdHJpYnV0aW9uIG9mIHNtYWxsZXN0IGNvbnZlcmdlbnQgY3RjZiBwYWlycyBhcm91bmQgZ2VuZSIpCmBgYAojIyMjIEZpbHRlcmluZyBsb29wcyB0aGF0IGZhbGwgd2l0aGluIENUQ0YgYm91bmRhcmllcwpgYGB7cn0KZmxhbmtTaXplIDwtIDEKZ2VuZS5UU1MudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLAogICAgICAgICAgICAgICAgVFNTc3RhcnQgPSBUU1MgLSBmbGFua1NpemUsCiAgICAgICAgICAgICAgICBUU1NlbmQgPSBUU1MgKyBmbGFua1NpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIFRTU3N0YXJ0LCBUU1NlbmQsIFY0LCBWNSwgVjYpCmNvbG5hbWVzKGdlbmUuVFNTLnRiKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgInN0cmFuZCIsICJnZW5lIiwgImVuc2VtYmwiKQpnZW5lRW5zZW1ibFBhaXIgPC0gZ2VuZS5UU1MudGIgJT4lIGRwbHlyOjpzZWxlY3QoZ2VuZSwgZW5zZW1ibCkKCmJvdW5kYXJ5LnBhaXIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJ0c3NfY29udmVyZ2VudF9jdGNmX21vdGlmX3BhaXJzLmJlZHBlIikpCmNvbG5hbWVzKGJvdW5kYXJ5LnBhaXIpIDwtIGMoImJvdW5kYXJ5X2Nocm9tMSIsICJib3VuZGFyeV9zdGFydDEiLCAiYm91bmRhcnlfZW5kMSIsICJib3VuZGFyeV9jaHJvbTIiLCAiYm91bmRhcnlfc3RhcnQyIiwgImJvdW5kYXJ5X2VuZDIiLCAiZW5zZW1ibCIpCmJvdW5kYXJ5LnBhaXIgPC0gYm91bmRhcnkucGFpciAlPiUgZHBseXI6OmxlZnRfam9pbihnZW5lRW5zZW1ibFBhaXIsIGJ5ID0gYygiZW5zZW1ibCIpKQoKCiMgSW1wb3J0aW5nIGxvb3AgZ2VuZSBhbm5vdGF0aW9uCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNCwgNSwgNiwgMTEsIDEyLCAyNCwgMjksIDMxKSkgJT4lIHVubmVzdChnZW5lKQoKCmRhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKGJvdW5kYXJ5LnBhaXIsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibCIpKQoKZGF0YSA8LSBkYXRhICU+JSByb3d3aXNlKCkgJT4lIGRwbHlyOjptdXRhdGUoaXNXaXRoaW5MZWZ0QmQgPSAoYm91bmRhcnlfc3RhcnQxIDw9IG1pbihlbmQxLCBlbmQyKSksCiAgICAgICAgICAgICAgICAgICAgICAgaXNXaXRoaW5SaWdodEJkID0gKGJvdW5kYXJ5X2VuZDIgPj0gbWF4KHN0YXJ0MSwgc3RhcnQyKSksCiAgICAgICAgICAgICAgICAgICAgICAgaXNXaXRoaW5CZCA9IGlzV2l0aGluTGVmdEJkICYgaXNXaXRoaW5SaWdodEJkKQpkYXRhIDwtIGRhdGEgJT4lIGRyb3BfbmEoKQoKCmdncGxvdChkYXRhLCBhZXMoeCA9IERNU08sIHkgPSBkVEFHKSkgKyBnZW9tX3BvaW50KCkgKyBjb29yZF9maXhlZCgpICsgIAogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyBmYWNldF93cmFwKH4gaXNXaXRoaW5CZCkKCmdncGxvdChkYXRhLCBhZXMoeCA9IGlzV2l0aGluQmQsIHkgPSBkaWZmX2RUQUdfRE1TTywgZmlsbCA9IGlzV2l0aGluQmQpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEpICsgdGhlbWVfY2xhc3NpYygpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihpc1dpdGhpbkJkID09Z3JvdXAxKSApJGRpZmZfZFRBR19ETVNPCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGlzV2l0aGluQmQgPT1ncm91cDIpICkkZGlmZl9kVEFHX0RNU08KICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CgpnZXRQdmFsV2lsY294KGRhdGEsIFRSVUUsIEZBTFNFKQoKCiMgUHJvcG9ydGlvbiBvZiB0aG9zZSBnZW5lIGJldHdlZW4gZ3JvdXAxIGFuZCBncm91cDIKZGF0YS5pc1dpdGhpbkJkIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoaXNXaXRoaW5CZCkKCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCnN1bShnZW5lLmdyb3VwMSAlaW4lIGRhdGEuaXNXaXRoaW5CZCRnZW5lKS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMAoKc3VtKGdlbmUuZ3JvdXAyICVpbiUgZGF0YS5pc1dpdGhpbkJkJGdlbmUpL2xlbmd0aChnZW5lLmdyb3VwMikqMTAwCgojIENoZWNraW5nIHNpemUgb2YgdGhvc2UgbG9vcHMKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKQoKZ2dwbG90KGRhdGEsIGFlcyh4ID0gaXNXaXRoaW5CZCwgeSA9IGRpc3RhbmNlLCBmaWxsID0gaXNXaXRoaW5CZCkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkgKyB0aGVtZV9jbGFzc2ljKCkKCgoKYGBgCgoKIyMjIFsyLjM1XSBDaGVja2luZyBDVENGIG1vdGlmIHByZXNlbmNlIGF0IGdlbmUgVFNTCmBgYHtyfQpmbGFua1NpemUgPC0gMi41ZTMKZ2VuZS50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMyksCiAgICAgICAgICAgICAgICBUU1NzdGFydCA9IFRTUyAtIGZsYW5rU2l6ZSwKICAgICAgICAgICAgICAgIFRTU2VuZCA9IFRTUyArIGZsYW5rU2l6ZSkgJT4lCiAgZHBseXI6OnNlbGVjdChWMSwgVFNTc3RhcnQsIFRTU2VuZCwgVjYsIFY1KQpjb2xuYW1lcyhnZW5lLnRiKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgImVuc2VtYmwiLCAiZ2VuZSIpCgpnZW5lLmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ2VuZS5ncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpUU1MxbWIuZ3JvdXAxLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShnZW5lLnRiICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmwgJWluJSBnZW5lLmdyb3VwMSksIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpClRTUzFtYi5ncm91cDIuZ3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGdlbmUuZ3JvdXAyKSwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRSkKCgpjdGNmLnBlYWsgPC0gZnJlYWQoaGVyZShyZWZEaXIsICIzMzI0OF9DVENGXzA3LTcyOV9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay5tb3RpZkFubm90YXRlZC5iZWQiKSkKY29sbmFtZXMoY3RjZi5wZWFrKSA8LSBjKCJjaHIiLCAic3RhcnQiLCAiZW5kIiwgIm1vdGlmIikKY3RjZi5wZWFrLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShjdGNmLnBlYWspCgoKcHJpbnQoIistMi41a2IgVFNTIG92ZXJsYSB3aXRoIENUQ0YgcGVhayIpCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAxLmdyLCBjdGNmLnBlYWsuZ3IpKSkpL2xlbmd0aChnZW5lLmdyb3VwMSkqMTAwCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAyLmdyLCBjdGNmLnBlYWsuZ3IpKSkpL2xlbmd0aChnZW5lLmdyb3VwMikqMTAwCgoKCmN0Y2YucGVhay5nciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoY3RjZi5wZWFrICU+JSBkcGx5cjo6ZmlsdGVyKG1vdGlmICE9ICJub25lIikpCnByaW50KCIrLTIuNWtiIFRTUyBvdmVybGEgd2l0aCBDVENGIHBlYWsgd2l0aCBtb3RpZiIpCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAxLmdyLCBjdGNmLnBlYWsuZ3IpKSkpL2xlbmd0aChnZW5lLmdyb3VwMSkqMTAwCmxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyhUU1MxbWIuZ3JvdXAyLmdyLCBjdGNmLnBlYWsuZ3IpKSkpL2xlbmd0aChnZW5lLmdyb3VwMikqMTAwCgoKCgpgYGAKCiMjIyBbMi4zNl0gRmluZGluZyBmYXJ0aGVzdCBQLVMKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCmRpZmZDdXRvZmYgPC0gMC4yCmdlbmVBbm5vRGF0YSA8LSBsb2FkTG9vcEFubm9EYXRhKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAobmFtZSwgIl9wLW5fZW5zZW1ibExpc3QudHN2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZDdXRvZmYgPSBkaWZmQ3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1QIiwgIlAtRSIsICJQLVMiLCAiUC1YIikpICU+JQogIGRwbHlyOjpzZWxlY3QoYygxLCAyLCAzLCA0LCA1LCA2LCA3LCAxMSwgMTIsIDI0LCAyOSwgMzEpKSAlPiUgdW5uZXN0KGdlbmUpCgoKZ2VuZS5UU1MudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpKSAlPiUKICBkcGx5cjo6c2VsZWN0KFY2LCBUU1MpCmNvbG5hbWVzKGdlbmUuVFNTLnRiKSA8LSBjKCJlbnNlbWJsIiwgIlRTUyIpCgoKZ2VuZUFubm9EYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihnZW5lLlRTUy50YiwgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsIikpCgpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlMSA9IChzdGFydDEgKyBlbmQxKS8yIC0gVFNTLAogICAgICAgICAgICAgICAgZGlzdGFuY2UyID0gKHN0YXJ0MiArIGVuZDIpLzIgLSBUU1MsCiAgICAgICAgICAgICAgICBkaXN0YW5jZSA9IGlmX2Vsc2UoYWJzKGRpc3RhbmNlMSkgPiBhYnMoZGlzdGFuY2UyKSwgZGlzdGFuY2UxLCBkaXN0YW5jZTIpKQoKcmVzdWx0IDwtIGdlbmVBbm5vRGF0YSAlPiUKICBmaWx0ZXIoQW5ubzIgPT0gIlAtUyIpICU+JQogIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcmlzZSgKICAgIGZhclJpZ2h0ID0gaWYgKGFueShkaXN0YW5jZSA+IDApKSBtYXgoZGlzdGFuY2VbZGlzdGFuY2UgPiAwXSkgZWxzZSAwLCAgIyBSZXR1cm4gMCBpZiBubyBwb3NpdGl2ZSBkaXN0YW5jZQogICAgZmFyTGVmdCA9IGlmIChhbnkoZGlzdGFuY2UgPCAwKSkgbWluKGRpc3RhbmNlW2Rpc3RhbmNlIDwgMF0pIGVsc2UgMCAgIyBSZXR1cm4gMCBpZiBubyBuZWdhdGl2ZSBkaXN0YW5jZQogICkgJT4lCiAgdW5ncm91cCgpCgpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSBsZWZ0X2pvaW4ocmVzdWx0LCBieSA9IGMoImdlbmUiKSkKCmdlbmVBbm5vRGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIikpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oaXMubmEoZmFyUmlnaHQpIH4gIk5vIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkaXN0YW5jZSA+IGZhckxlZnQpICYgKGRpc3RhbmNlIDwgZmFyUmlnaHQpIH4gIldpdGhpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk91dHNpZGUiKSwKICAgICAgICAgICAgICAgIHNpemUgPSBzdGFydDIgLSBzdGFydDEpCgpkYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgaWQsIHNpemUpICU+JSBkaXN0aW5jdCgpCmFuY2hvci5kYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgY2hyb20yLCBzdGFydDIsIGVuZDIsIGdyb3VwKSAlPiUgZGlzdGluY3QoKQoKdGVtcDEgPC0gYW5jaG9yLmRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIk5vIikgJT4lIGRwbHlyOjpzZWxlY3QoLWdyb3VwKQpmd3JpdGUodGVtcDEsIGhlcmUoY29uc2Vuc3VzRGlyLCAiaW5zdWxhdGVkX2RvbWFpbl9wc19uby5iZWRwZSIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKdGVtcDIgPC0gYW5jaG9yLmRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIldpdGhpbiIpICU+JSBkcGx5cjo6c2VsZWN0KC1ncm91cCkKZndyaXRlKHRlbXAyLCBoZXJlKGNvbnNlbnN1c0RpciwgImluc3VsYXRlZF9kb21haW5fcHNfd2l0aGluLmJlZHBlIiksIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQp0ZW1wMyA8LSBhbmNob3IuZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiT3V0c2lkZSIpICU+JSBkcGx5cjo6c2VsZWN0KC1ncm91cCkKZndyaXRlKHRlbXAzLCBoZXJlKGNvbnNlbnN1c0RpciwgImluc3VsYXRlZF9kb21haW5fcHNfb3V0c2lkZS5iZWRwZSIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkc2l6ZQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRzaXplCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKIyBjb252UHZhbHVlKGdldFB2YWxXaWxjb3goZGF0YSwgIm5vQm91bmRhcnkiLCAid2l0aGluQm91bmRhcnkiKSkKIyBjb252UHZhbHVlKGdldFB2YWxXaWxjb3goZGF0YSwgIm5vQm91bmRhcnkiLCAib3V0c2lkZUJvdW5kYXJ5IikpCiMgY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJvdXRzaWRlQm91bmRhcnkiLCAid2l0aGluQm91bmRhcnkiKSkKCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gc2l6ZSwgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX3Zpb2xpbihsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwgYWxwaGEgPSAuNCwgLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIHN0YXRfc3VtbWFyeSgKICAgICAgYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLAogICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICAgICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk1MCIsICIjNUVDOTYyIiwgIiM1RUM5NjIiKSkgKwoKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksICAgIAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgK2xhYnMoeSA9ICJMb29wIHNpemUiKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uQm91bmRhcnlfc2l6ZSIpCndpZHRoIDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQogIAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGRpZmZfZFRBR19ETVNPCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJGRpZmZfZFRBR19ETVNPCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKZGF0YSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGlkLCBkaWZmX2RUQUdfRE1TTykgJT4lIGRpc3RpbmN0KCkKCiMgY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJub0JvdW5kYXJ5IiwgIndpdGhpbkJvdW5kYXJ5IikpCiMgY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJub0JvdW5kYXJ5IiwgIm91dHNpZGVCb3VuZGFyeSIpKQojIGNvbnZQdmFsdWUoZ2V0UHZhbFdpbGNveChkYXRhLCAib3V0c2lkZUJvdW5kYXJ5IiwgIndpdGhpbkJvdW5kYXJ5IikpCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlmZl9kVEFHX0RNU08sIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV92aW9saW4obGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIGFscGhhID0gLjQsICwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5NTAiLCAiIzVFQzk2MiIsICIjNUVDOTYyIikpICsKCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLCAgICAKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApICtsYWJzKHkgPSAizpQgbG9vcCBzY29yZSIpICArICAgIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsCiAgICAgICAgICAgICBhbHBoYSA9IDEsCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtMC4yLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuOCwgMC41KSkKICAgIApmaWxlTmFtZSA8LSBwYXN0ZTAoImluc3VsYXRpb25Cb3VuZGFyeV9kZWx0YSIpCnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpICAKICAKICAKICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgCiAgICAKICAgIG1pblZhbHVlIDwtIC00CiAgb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTywKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPSBsb2dfb2JzZXhwX0E0ODUgLSBsb2dfb2JzZXhwX0RNU08pCgpnZW5lQW5ub0RhdGEgPC0gZ2VuZUFubm9EYXRhICU+JSBsZWZ0X2pvaW4ob2JzZXhwLCBieSA9IGMoImlkIikpCgpkYXRhIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgaWQsIGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08pICU+JSBkaXN0aW5jdCgpCgoKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08KICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTwogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCiMgY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJub0JvdW5kYXJ5IiwgIndpdGhpbkJvdW5kYXJ5IikpCiMgY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJub0JvdW5kYXJ5IiwgIm91dHNpZGVCb3VuZGFyeSIpKQojIGNvbnZQdmFsdWUoZ2V0UHZhbFdpbGNveChkYXRhLCAib3V0c2lkZUJvdW5kYXJ5IiwgIndpdGhpbkJvdW5kYXJ5IikpCiMgCgpwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGdyb3VwLCB5ID0gbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTywgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX3Zpb2xpbihsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwgYWxwaGEgPSAuNCwgLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BLCAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgdGhlbWVfY2xhc3NpYygpICsgCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGdyb3VwID0gZ3JvdXApLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAwLjUsCiAgICBmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKC4zKQogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk1MCIsICIjNUVDOTYyIiwgIiM1RUM5NjIiKSkgKwoKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksICAgIAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgK2xhYnMoeSA9ICJsb2cyKGZjIG9mIG9icy9leHApIikgICsgICAgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwKICAgICAgICAgICAgIGFscGhhID0gMSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiKSArIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMiwgMikpCiAgICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uQm91bmRhcnlfb2JzZXhwIikKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkgIAoKCgoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCmdlbmUud2l0aGluQm91bmRhcnkgPC0gdW5pcXVlKChnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIndpdGhpbkJvdW5kYXJ5IikpJGdlbmUpCmdlbmUub3V0c2lkZUJvdW5kYXJ5IDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJvdXRzaWRlQm91bmRhcnkiKSkkZ2VuZSkKZ2VuZS5ub0JvdW5kYXJ5IDwtIHVuaXF1ZSgoZ2VuZUFubm9EYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJub0JvdW5kYXJ5IikpJGdlbmUpCgpnZW5lLndCb3VuZGFyeSA8LSB1bmlxdWUoYyhnZW5lLndpdGhpbkJvdW5kYXJ5LCBnZW5lLm91dHNpZGVCb3VuZGFyeSkpCgpnZW5lLmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ2VuZS5ncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpwcmludCgicGVyYyBvZiBnZW5lIHdpdGggbG9vcCB3aXRoaW4gQm91bmRhcnkiKQpzdW0oZ2VuZS5ncm91cDEgJWluJSBnZW5lLndpdGhpbkJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApzdW0oZ2VuZS5ncm91cDIgJWluJSBnZW5lLndpdGhpbkJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDIpKjEwMAoKcHJpbnQoInBlcmMgb2YgZ2VuZSB3aXRoIGxvb3Agb3V0c2lkZSBCb3VuZGFyeSIpCnN1bShnZW5lLmdyb3VwMSAlaW4lIGdlbmUub3V0c2lkZUJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApzdW0oZ2VuZS5ncm91cDIgJWluJSBnZW5lLm91dHNpZGVCb3VuZGFyeSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCnByaW50KCJwZXJjIG9mIGdlbmUgd2l0aCBsb29wIHdpdGggbm8gQm91bmRhcnkiKQpzdW0oZ2VuZS5ncm91cDEgJWluJSBnZW5lLm5vQm91bmRhcnkpL2xlbmd0aChnZW5lLmdyb3VwMSkqMTAwCnN1bShnZW5lLmdyb3VwMiAlaW4lIGdlbmUubm9Cb3VuZGFyeSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oCiAgICBlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lLndCb3VuZGFyeSB+ICJ3aXRoaW5Cb3VuZGFyeSIsCiAgICBlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lLm5vQm91bmRhcnkgfiAibm9Cb3VuZGFyeSIsCiAgICBUUlVFIH4gTkEKICApKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpICU+JQogIGRwbHlyOjptdXRhdGUoYWJzTG9nMkZDID0gYWJzKGxvZzJGb2xkQ2hhbmdlKSkKCgpnZ3Bsb3QoZGlmZi5STkEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBsb2cyRm9sZENoYW5nZSkpICsgZ2VvbV92aW9saW4oKSArIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSkKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRhYnNMb2cyRkMKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkYWJzTG9nMkZDCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQpjb252UHZhbHVlKGdldFB2YWxXaWxjb3goZGlmZi5STkEsICJ3aXRoaW5Cb3VuZGFyeSIsICJub0JvdW5kYXJ5IikpCgoKIyBDcmVhdGUgdGhlIENERiBwbG90CnAgPC0gZ2dwbG90KGRpZmYuUk5BLCBhZXMoeCA9IGFic0xvZzJGQywgY29sb3IgPSBncm91cCkpICsKc3RhdF9lY2RmKHNpemUgPSAwLjQgKSArICMgVXNlIHN0YXRfZWNkZiB0byBwbG90IHRoZSBlbXBpcmljYWwgQ0RGCiAgbGFicygKICAgIHggPSAiQWJzb2x1dGUgbG9nMihmb2xkIGNoYW5nZSkiLAogICAgeSA9ICJDdW11bGF0aXZlIFByb2JhYmlsaXR5IgogICkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMC41KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICMgQ2xlYW4gdGhlbWUKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfY2RmX2luc3VsYXRpb25Cb3VuZGFyeSIpCndpZHRoIDwtIHBhbmVsU2l6ZSgyLjUpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKCgojIyMgQ2hlY2tpbmcgY2hhcmFjdGVyc3RpY3Mgb2YgYW5jaG9ycwp0ZW1wMSA8LSBhbmNob3IuZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAibm9Cb3VuZGFyeSIpICU+JSBkcGx5cjo6c2VsZWN0KC1ncm91cCkKYW5jaG9yLm5vQm91bmRhcnkgPC0gZXh0cmFjdEFuY2hvcih0ZW1wMSkKCnRlbXAyIDwtIGFuY2hvci5kYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJ3aXRoaW5Cb3VuZGFyeSIpICU+JSBkcGx5cjo6c2VsZWN0KC1ncm91cCkKYW5jaG9yLndpdGhpbkJvdW5kYXJ5IDwtIGV4dHJhY3RBbmNob3IodGVtcDIpCgp0ZW1wMyA8LSBhbmNob3IuZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAib3V0c2lkZUJvdW5kYXJ5IikgJT4lIGRwbHlyOjpzZWxlY3QoLWdyb3VwKQphbmNob3Iub3V0c2lkZUJvdW5kYXJ5IDwtIGV4dHJhY3RBbmNob3IodGVtcDMpCgoKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGxvb3AgPT1ncm91cDEpICkkc3VtU2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIobG9vcCA9PWdyb3VwMikgKSRzdW1TY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCmdldFN1bVNjb3JlcyA8LSBmdW5jdGlvbih0cmFjaywgYW5jaG9yKSB7CiAgIyBGaW5kIG92ZXJsYXBzIGJldHdlZW4gYWxsIGFuY2hvcnMgYW5kIHRyYWNrIHJlZ2lvbnMgYXQgb25jZQogIG92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3IsIHRyYWNrKQogIAogICMgRXh0cmFjdCB0aGUgc2NvcmVzIGFuZCBjb3JyZXNwb25kaW5nIGFuY2hvciBpbmRpY2VzCiAgYW5jaG9yX2luZGljZXMgPC0gcXVlcnlIaXRzKG92ZXJsYXBzKQogIHRyYWNrX3Njb3JlcyA8LSBzY29yZSh0cmFjaylbc3ViamVjdEhpdHMob3ZlcmxhcHMpXQogIAogICMgVXNlIHRhcHBseSB0byBjYWxjdWxhdGUgdGhlIG1lZGlhbiBzY29yZXMgZm9yIGVhY2ggYW5jaG9yCiAgbWVkaWFuX3Njb3JlcyA8LSB0YXBwbHkodHJhY2tfc2NvcmVzLCBhbmNob3JfaW5kaWNlcywgbWVhbiwgbmEucm0gPSBUUlVFKQogIAogICMgSW5pdGlhbGl6ZSBhIG51bWVyaWMgdmVjdG9yIHRvIHN0b3JlIHRoZSBtZWRpYW4gc2NvcmVzIGZvciBlYWNoIGFuY2hvcgogIGFsbF9tZWRpYW5fc2NvcmVzIDwtIHJlcChOQSwgbGVuZ3RoKGFuY2hvcikpCiAgCiAgIyBQb3B1bGF0ZSB0aGUgbWVkaWFuIHNjb3JlcyBmb3IgdGhlIGFuY2hvcnMgdGhhdCBoYXZlIG92ZXJsYXBzCiAgYWxsX21lZGlhbl9zY29yZXNbYXMubnVtZXJpYyhuYW1lcyhtZWRpYW5fc2NvcmVzKSldIDwtIG1lZGlhbl9zY29yZXMKICAKICByZXR1cm4oYWxsX21lZGlhbl9zY29yZXMpCn0KCnBsb3RTdW1TY29yZXNCaW5hcnkgPC0gZnVuY3Rpb24odHJhY2ssIHBlYWssIG5hbWUsIGFuY2hvcjEsIGFuY2hvcjIsIGFuY2hvcjMpewogIHBlYWtUcmFjayA8LSB0cmFja1t1bmlxdWUocXVlcnlIaXRzKGZpbmRPdmVybGFwcyh0cmFjaywgcGVhaykpKV0KICBhIDwtIGdldFN1bVNjb3JlcyhwZWFrVHJhY2ssIGFuY2hvcjEpCiAgYiA8LSBnZXRTdW1TY29yZXMocGVha1RyYWNrLCBhbmNob3IyKQogIGMgPC0gZ2V0U3VtU2NvcmVzKHBlYWtUcmFjaywgYW5jaG9yMykKICBhLnRiIDwtIHRpYmJsZShsb29wID0gIm5vQm91bmRhcnkiLAogICAgICAgICAgICAgICAgIHN1bVNjb3JlID0gYSkKICBiLnRiIDwtIHRpYmJsZShsb29wID0gIndpdGhCb3VuZGFyeSIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBiKQogIGMudGIgPC0gdGliYmxlKGxvb3AgPSAib3V0c2lkZUJvdW5kYXJ5IiwKICAgICAgICAgICAgICAgICBzdW1TY29yZSA9IGMpCiAgCiAgZGF0YSA8LSBiaW5kX3Jvd3MoYS50YiwgYi50YiwgYy50YikgJT4lIGRyb3BfbmEoKQogIGRhdGEkbG9vcCA8LSBmYWN0b3IoZGF0YSRsb29wLCBsZXZlbHMgPSBjKCJub0JvdW5kYXJ5IiwgIndpdGhCb3VuZGFyeSIsICJvdXRzaWRlQm91bmRhcnkiKSkKICAKICBwMTIgPC0gZ2V0UHZhbFdpbGNveChkYXRhLCAibm9Cb3VuZGFyeSIsICJ3aXRoQm91bmRhcnkiKQogIHAxMyA8LSBnZXRQdmFsV2lsY294KGRhdGEsICJub0JvdW5kYXJ5IiwgIm91dHNpZGVCb3VuZGFyeSIpCiAgcDIzIDwtIGdldFB2YWxXaWxjb3goZGF0YSwgIndpdGhCb3VuZGFyeSIsICJvdXRzaWRlQm91bmRhcnkiKQogIHAgPC0gIGdncGxvdChkYXRhLCBhZXMoeCA9IGxvb3AsIHkgPSBzdW1TY29yZSkpICsgCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gcGFzdGUwKG5hbWUsICJcbmxvZyhhdmcgcGVhayBzY29yZSBwZXIgYW5jaG9yKSIpKSArCiAgICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGxvb3ApLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDEsIG91dGxpZXIuc3Ryb2tlID0gTkEpICsgdGhlbWVfY2xhc3NpYygpICsKICAgIHN0YXRfc3VtbWFyeSgKICAgICAgYWVzKGdyb3VwID0gbG9vcCksIGZ1biA9IG1lYW4sCiAgICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMSwKICAgICAgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIKICAgICkgKyB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgICApLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgICApLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgICApLAogICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKSArIAogICAgI2Nvb3JkX2NhcnRlc2lhbih5bGltID0gYyhxdWFudGlsZShkYXRhJHN1bVNjb3JlLCAwLjApLCBxdWFudGlsZShkYXRhJHN1bVNjb3JlLCAwLjk5KSkpICsgCiAgICBhbm5vdGF0ZSgKICAgICAgInRleHQiLCB4ID0gMSwgeSA9IHF1YW50aWxlKGRhdGEkc3VtU2NvcmUsIDAuNSksCiAgICAgIGxhYmVsID0gcGFzdGUwKCJwMTI6ICIsIGNvbnZQdmFsdWUocDEyKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgInAxMzogIiwgY29udlB2YWx1ZShwMTMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAicDIzOiAiLCBjb252UHZhbHVlKHAyMykpLAogICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMKICAgICkgCiAgIysgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoIkNoSVBfcGVha19hdmdQZWFrU2NvcmVfYm91bmRhcnlBbmNob3JfIiwgbmFtZSkKICB3aWR0aCA8LSBwYW5lbFNpemUoMikqbW1Ub0luY2gKICBoZWlnaHQgPC0gcGFuZWxTaXplKDIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCiMgU3VtIHBlYWsgc2NvcmUKIyMjIwp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI1NV9IM0s0bWUzXzA0LTc0NV9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTVfSDNLNG1lM18wNC03NDVfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJIM0s0bWUzIiwgYW5jaG9yLm5vQm91bmRhcnksIGFuY2hvci53aXRoaW5Cb3VuZGFyeSwgYW5jaG9yLm91dHNpZGVCb3VuZGFyeSkKCnRyYWNrIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIkdTTTI0Mzg0NzZfRUMtREctMzQ1OC1IM0syN0FDX0FTWU5fMS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiR1NNMjQzODQ3Nl9FQy1ERy0zNDU4LUgzSzI3QUNfQVNZTl8xLm5hcnJvd1BlYWsuYmVkIikpCiNwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiSDNLMjdhYyIpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJIM0syN2FjIiwgYW5jaG9yLm5vQm91bmRhcnksIGFuY2hvci53aXRoaW5Cb3VuZGFyeSwgYW5jaG9yLm91dHNpZGVCb3VuZGFyeSkKCnRyYWNrIDwtIGltcG9ydChoZXJlKHJlZkRpciwgIkdTTTI2ODM0NDBfSjFfSDNLMTRhY19tbTEwTGlmdGVkLmJsYWNrLmJ3IiksIGZvcm1hdCA9ICJCaWdXaWciKQpwZWFrIDwtIGltcG9ydFBlYWsoaGVyZShyZWZEaXIsICJHU00yNjgzNDQwX0oxX0gzSzE0YWNfbW0xMExpZnRlZC5iZWQiKSkKI3Bsb3RTdW1TY29yZXModHJhY2ssIHBlYWssICJIM0sxNGFjIikKcGxvdFN1bVNjb3Jlc0JpbmFyeSh0cmFjaywgcGVhaywgIkgzSzE0YWMiLCBhbmNob3Iubm9Cb3VuZGFyeSwgYW5jaG9yLndpdGhpbkJvdW5kYXJ5LCBhbmNob3Iub3V0c2lkZUJvdW5kYXJ5KQoKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF90cmltX3EyMF9kZWR1cF9ibGFja19kZXB0aE5vcm0uYnciKSwgZm9ybWF0ID0gIkJpZ1dpZyIpCnBlYWsgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjQ4X0NUQ0ZfMDctNzI5X0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQojcGxvdFN1bVNjb3Jlcyh0cmFjaywgcGVhaywgIkNUQ0YiKQpwbG90U3VtU2NvcmVzQmluYXJ5KHRyYWNrLCBwZWFrLCAiQ1RDRiIsIGFuY2hvci5ub0JvdW5kYXJ5LCBhbmNob3Iud2l0aGluQm91bmRhcnksIGFuY2hvci5vdXRzaWRlQm91bmRhcnkpCgp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI1MF9SQUQyMV9hYjk5Ml9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTBfUkFEMjFfYWI5OTJfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCiNwbG90U3VtU2NvcmVzKHRyYWNrLCBwZWFrLCAiUkFEMjEiKQpwbG90U3VtU2NvcmVzQmluYXJ5KHRyYWNrLCBwZWFrLCAiUkFEMjEiLCBhbmNob3Iubm9Cb3VuZGFyeSwgYW5jaG9yLndpdGhpbkJvdW5kYXJ5LCBhbmNob3Iub3V0c2lkZUJvdW5kYXJ5KQoKCgojIyMjIyMjIyBMT0xBCmF0YWMgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJHU00zMTA2MjU3X0FUQUNfRVNDXzEuYmVkIikpICU+JSBkcGx5cjo6c2VsZWN0KFYxLCBWMiwgVjMpCmNvbG5hbWVzKGF0YWMpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiKQphdGFjLmdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShhdGFjKQoKIyBMT0FESU5HIExPT1BTCmxvb3AuYWxsIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeS50c3YiKSkgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIiwgIkUtRSIpKQphbmNob3IuYWxsIDwtIChleHRyYWN0QW5jaG9yKGxvb3AuYWxsKSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci5hbGwsIGF0YWMuZ3IpCmFuY2hvci5hbGwgPC0gcGludGVyc2VjdChhbmNob3IuYWxsW3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoYW5jaG9yLm5vQm91bmRhcnksIGF0YWMuZ3IpCmFuY2hvci5ub0JvdW5kYXJ5IDwtIHBpbnRlcnNlY3QoYW5jaG9yLm5vQm91bmRhcnlbcXVlcnlIaXRzKG92ZXJsYXBzKV0sIGF0YWMuZ3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGFuY2hvci53aXRoaW5Cb3VuZGFyeSwgYXRhYy5ncikKYW5jaG9yLndpdGhpbkJvdW5kYXJ5IDwtIHBpbnRlcnNlY3QoYW5jaG9yLndpdGhpbkJvdW5kYXJ5W3F1ZXJ5SGl0cyhvdmVybGFwcyldLCBhdGFjLmdyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhhbmNob3Iub3V0c2lkZUJvdW5kYXJ5LCBhdGFjLmdyKQphbmNob3Iub3V0c2lkZUJvdW5kYXJ5IDwtIHBpbnRlcnNlY3QoYW5jaG9yLm91dHNpZGVCb3VuZGFyeVtxdWVyeUhpdHMob3ZlcmxhcHMpXSwgYXRhYy5ncltzdWJqZWN0SGl0cyhvdmVybGFwcyldKQoKCgphbmNob3JzIDwtIGxpc3QoYW5jaG9yLm5vQm91bmRhcnksIGFuY2hvci53aXRoQm91bmRhcnksIGFuY2hvci5vdXRzaWRlQm91bmRhcnkpCnRicyA8LSBsaXN0KCkKdGVtcHMgPC0gbGlzdCgpCgphbHBoYSA8LSAwLjA1CgojIFByb2Nlc3MgY2x1c3RlcnMgYzEgdG8gYzgKZm9yIChpIGluIDE6MykgewogIAogIGFuY2hvciA8LSBhbmNob3JzW1tpXV0KICAjIFJ1biBMT0xBCiAgcmVzdWx0IDwtIHJ1bkxPTEEoYW5jaG9yLCBhbmNob3IuYWxsLCBsb2xhREIpCiAgdGIgPC0gYXNfdGliYmxlKHJlc3VsdCkKICAKICAjIEZpbHRlciBhbmQgc3VtbWFyaXplCiAgdGIgPC0gdGIgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHRhcmdldCA9IHRvdXBwZXIoYW50aWJvZHkpKSAlPiUKICAgIGZpbHRlcihzdHJfdG9fbG93ZXIoY2VsbFR5cGUpID09ICJlbWJyeW9uaWMgc3RlbSBjZWxsIikgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKHFWYWx1ZSA8IGFscGhhKSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh0YXJnZXQpICU+JQogICAgc2xpY2VfbWluKG1lYW5SbmssIHdpdGhfdGllcyA9IEZBTFNFKQogIAogICMgU3RvcmUgdGIKICB0YnNbW2ldXSA8LSB0YgogIAogICMgU2VsZWN0IGFuZCByZW5hbWUgb2Rkc1JhdGlvCiAgdGVtcCA8LSB0YiAlPiUgZHBseXI6OnNlbGVjdCh0YXJnZXQsIG9kZHNSYXRpbykKICBjb2xuYW1lcyh0ZW1wKSA8LSBjKCJ0YXJnZXQiLCBwYXN0ZTAoIk9SX2MiLCBpKSkKICAKICAjIFN0b3JlIHRlbXAKICB0ZW1wc1tbaV1dIDwtIHRlbXAKfQoKIyBNZXJnZSBhbGwgdGVtcCB0YWJsZXMgaW50byBvbmUKdGVtcCA8LSBSZWR1Y2UoZnVuY3Rpb24oeCwgeSkgZnVsbF9qb2luKHgsIHksIGJ5ID0gInRhcmdldCIpLCB0ZW1wcykgJT4lCiAgbXV0YXRlX2FsbCh+cmVwbGFjZV9uYSguLCAxKSkKY29sbmFtZXModGVtcCkgPC0gYygidGFyZ2V0IiwgIm5vQm91bmRhcnkiLCAid2l0aGluQm91bmRhcnkiLCAib3V0c2lkZUJvdW5kYXJ5IikKZGF0YSA8LSB0ZW1wICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoInRhcmdldCIpICU+JSBhcy5tYXRyaXgoKQoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoMSwgbWF4KGRhdGEpKSwgYygid2hpdGUiLCAicmVkIikpCgoKI2Z2aXpfbmJjbHVzdChkYXRhLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQoKcCA8LSBIZWF0bWFwKAogIGRhdGEsCiAgbmFtZSA9ICJPZGRzIFJhdGlvIiwgICAgICAgICAgICAgICAgICAgIyBOYW1lIG9mIHRoZSBoZWF0bWFwIGxlZ2VuZAogIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLCAgICAgICAgICAgICMgUmVtb3ZlIGNvbHVtbiBkZW5kcm9ncmFtCiAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogIGNvbCA9IGNvbF9mdW4sCiAgYm9yZGVyID0gVFJVRQopCmBgYAoKIyMjIFszLjM3XSBDaGVja2luZyBSQUQyMSBsZXZlbCBhdCB0c3MKYGBge3J9CnRzcy41a2IuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiVFNTX2JpbmFyeUdyb3VwMS5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShzdGFydCA9IChWMiArIFYzKS8yIC0gMjUwMCwKICAgICAgICAgICAgICAgIGVuZCA9IChWMiArIFYzKS8yICsgMjUwMCwKICAgICAgICAgICAgICAgIGNociA9IFYxKSAlPiUKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCkKdHNzLjVrYi5ncm91cDEgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRzcy41a2IuZ3JvdXAxKQoKdHNzLjVrYi5ncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJUU1NfYmluYXJ5R3JvdXAyLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHN0YXJ0ID0gKFYyICsgVjMpLzIgLSAyNTAwLAogICAgICAgICAgICAgICAgZW5kID0gKFYyICsgVjMpLzIgKyAyNTAwLAogICAgICAgICAgICAgICAgY2hyID0gVjEpICU+JQogIGRwbHlyOjpzZWxlY3QoY2hyLCBzdGFydCwgZW5kKQp0c3MuNWtiLmdyb3VwMiA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodHNzLjVrYi5ncm91cDIpCgoKcGxvdFN1bVNjb3Jlc0JpbmFyeSA8LSBmdW5jdGlvbih0cmFjaywgcGVhaywgbmFtZSwgYW5jaG9yMSwgYW5jaG9yMil7CiAgcGVha1RyYWNrIDwtIHRyYWNrW3VuaXF1ZShxdWVyeUhpdHMoZmluZE92ZXJsYXBzKHRyYWNrLCBwZWFrKSkpXQogIGEgPC0gZ2V0U3VtU2NvcmVzKHBlYWtUcmFjaywgYW5jaG9yMSkKICBiIDwtIGdldFN1bVNjb3JlcyhwZWFrVHJhY2ssIGFuY2hvcjIpCiAgYS50YiA8LSB0aWJibGUobG9vcCA9ICJncm91cDEiLAogICAgICAgICAgICAgICAgIHN1bVNjb3JlID0gYSkKICBiLnRiIDwtIHRpYmJsZShsb29wID0gImdyb3VwMiIsCiAgICAgICAgICAgICAgICAgc3VtU2NvcmUgPSBiKQogIAogIGRhdGEgPC0gYmluZF9yb3dzKGEudGIsIGIudGIpICU+JSBkcm9wX25hKCkKICBkYXRhJGxvb3AgPC0gZmFjdG9yKGRhdGEkbG9vcCwgbGV2ZWxzID0gYygiZ3JvdXAxIiwgImdyb3VwMiIpKQogIAogIHAxMiA8LSBnZXRQdmFsV2lsY294KGRhdGEsICJncm91cDEiLCAiZ3JvdXAyIikKICBwIDwtICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBsb29wLCB5ID0gc3VtU2NvcmUpKSArIAogICAgbGFicyh4ID0gTlVMTCwgeSA9IHBhc3RlMChuYW1lLCAiXG5sb2coYXZnIHBlYWsgc2NvcmUgcGVyIGFuY2hvcikiKSkgKwogICAgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBsb29wKSwgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgICBvdXRsaWVyLnNpemUgPSAxLCBvdXRsaWVyLnN0cm9rZSA9IE5BKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgICBzdGF0X3N1bW1hcnkoCiAgICAgIGFlcyhncm91cCA9IGxvb3ApLCBmdW4gPSBtZWFuLAogICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDEsCiAgICAgIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siCiAgICApICsgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IGZvbnRTaXplUywgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICAgICksCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgICAgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEKICAgICAgKSwKICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICAgKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICAgICksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICAgICkgKyAKICAgICNjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMocXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC4wKSwgcXVhbnRpbGUoZGF0YSRzdW1TY29yZSwgMC45OSkpKSArIAogICAgYW5ub3RhdGUoCiAgICAgICJ0ZXh0IiwgeCA9IDEsIHkgPSBxdWFudGlsZShkYXRhJHN1bVNjb3JlLCAwLjUpLAogICAgICBsYWJlbCA9IHBhc3RlMCgicDEyOiAiLCBjb252UHZhbHVlKHAxMikpLAogICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDMKICAgICkgCiAgIysgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikKICAKICBmaWxlTmFtZSA8LSBwYXN0ZTAoIkNoSVBfcGVha19hdmdQZWFrU2NvcmVfYmluYXJ5R3JvdXBfIiwgbmFtZSkKICB3aWR0aCA8LSBwYW5lbFNpemUoMikqbW1Ub0luY2gKICBoZWlnaHQgPC0gcGFuZWxTaXplKDIpKm1tVG9JbmNoCiAgcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCiAgcHJpbnQocCkKICBkZXYub2ZmKCkKICBzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQogIHByaW50KHApCiAgZGV2Lm9mZigpCn0KCiMgU3VtIHBlYWsgc2NvcmUKIyMjIwp0cmFjayA8LSBpbXBvcnQoaGVyZShyZWZEaXIsICIzMzI0OF9DVENGXzA3LTcyOV9CcnVjZS00X3RyaW1fcTIwX2RlZHVwX2JsYWNrX2RlcHRoTm9ybS5idyIpLCBmb3JtYXQgPSAiQmlnV2lnIikKcGVhayA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNDhfQ1RDRl8wNy03MjlfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCnBsb3RTdW1TY29yZXNCaW5hcnkodHJhY2ssIHBlYWssICJDVENGIiwgdHNzLjVrYi5ncm91cDEsIHRzcy41a2IuZ3JvdXAyKQoKdHJhY2sgPC0gaW1wb3J0KGhlcmUocmVmRGlyLCAiMzMyNTBfUkFEMjFfYWI5OTJfQnJ1Y2UtNF90cmltX3EyMF9kZWR1cF9ibGFja19kZXB0aE5vcm0uYnciKSwgZm9ybWF0ID0gIkJpZ1dpZyIpCnBlYWsgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQpwbG90U3VtU2NvcmVzQmluYXJ5KHRyYWNrLCBwZWFrLCAiUkFEMjEiLCB0c3MuNWtiLmdyb3VwMSwgdHNzLjVrYi5ncm91cDIpCgoKCmBgYAoKIyMjIFszLjM4XSBTdHJpcGUgcGVyY2VudGFnZQpgYGB7cn0KIyBDcmVhdGUgdGhlIGRhdGEKZGF0YSA8LSBkYXRhLmZyYW1lKAogIEdyb3VwID0gYygiR3JvdXAxIiwgIkdyb3VwMiIpLAogIFZhbHVlID0gYygzMS4wMywgMTAuNjQpCikKCiMgQ3JlYXRlIHRoZSBiYXIgcGxvdApwIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IEdyb3VwLCB5ID0gVmFsdWUsIGZpbGwgPSBHcm91cCkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSAwLjcsIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiKSArICMgVXNlIGlkZW50aXR5IGZvciByYXcgdmFsdWVzCiAgbGFicyh5ID0gIiUgb2YgVFNTIG9uIHN0cmlwZSIpICsgCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJwZXJjX29uX3N0cmlwZV9iaW5hcnlHcm91cCIpCndpZHRoIDwtIHBhbmVsU2l6ZSgxLjI1KSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuMikqbW1Ub0luY2gKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKIyMjWzMuMzldIFNwbGl0dGluZyBiZWRwZQpgYGB7cn0KdGVtcCA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMikpCmdlbmVMaXN0IDwtICh0ZW1wICU+JSBkcGx5cjo6ZmlsdGVyKGV4dGVybmFsX2dlbmVfbmFtZSAlaW4lIGMoIktsZjQiLCAiVGJ4MyIsICJKdW4iLCAiRm9zbDIiLCAiTXljIiwgIlBobGRhMSIpKSkkZW5zZW1ibF9nZW5lX2lkCgojIExPQUQgQU5OT1RBVEVEIExPT1AKbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSklPiUKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxKQoKZmlsdGVyZWRMb29wIDwtIGdlbmVBbm5vRGF0YSAlPiUgdW5uZXN0KGdlbmUpICU+JSBkcGx5cjo6ZmlsdGVyKGdlbmUgJWluJSBnZW5lTGlzdCkKZndyaXRlKGZpbHRlcmVkTG9vcCwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgiUC1OX3NlbGVjdGVkR2VuZS5iZWRwZSIpKSwgCiAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQogIAp0ZW1wbG9vcCA8LSBmaWx0ZXJlZExvb3AgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJQLVAiLCAiUC1FIikpCmZ3cml0ZSh0ZW1wbG9vcCwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgiUC1QRV9zZWxlY3RlZEdlbmUuYmVkcGUiKSksIAogICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKICAKdGVtcGxvb3AgPC0gZmlsdGVyZWRMb29wICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1TIikpCmZ3cml0ZSh0ZW1wbG9vcCwgaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgiUC1TX3NlbGVjdGVkR2VuZS5iZWRwZSIpKSwgCiAgICAgICAgIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIyBbMy40MF0gRmluZGluZyBsYXJnZXN0IGVuY29tcGFzc2luZyBTLVMKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgojIElNUE9SVCBTLVMgbG9vcHMKYWxsTG9vcHMgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5LnRzdiIpKQpzdHJMb29wcyA8LSBhbGxMb29wcyAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlMtUyIpKQp0ZW1wIDwtIHN0ckxvb3BzICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgNikpCmNvbG5hbWVzKHRlbXApIDwtIGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIpCnN0ckxvb3BzR3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHRlbXApCgojIElNUE9SVCBUU1MKZmxhbmtTaXplIDwtIDEwCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLAogICAgICAgICAgICAgICAgVFNTc3RhcnQgPSBUU1MgLSBmbGFua1NpemUsCiAgICAgICAgICAgICAgICBUU1NlbmQgPSBUU1MgKyBmbGFua1NpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjEsIFRTU3N0YXJ0LCBUU1NlbmQsIFY2LCBWNSkKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImVuc2VtYmwiLCAiZ2VuZSIpCmdlbmVHciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZ2VuZS50Yiwga2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRSkKCgojIEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBsb29wcyBhbmQgVFNTCm92ZXJsYXBzIDwtIGZpbmRPdmVybGFwcyhnZW5lR3IsIHN0ckxvb3BzR3IpCgojIEFubm90YXRlIG92ZXJsYXBzCnRzc193aXRoX2xvb3BzIDwtIGdlbmVHcltxdWVyeUhpdHMob3ZlcmxhcHMpXQpsb29wc193aXRoX3RzcyA8LSBzdHJMb29wc0dyW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0KCiMgQ29tYmluZSBpbnRvIGEgZGF0YSBmcmFtZSBmb3IgcHJvY2Vzc2luZwpsb29wX2RhdGEgPC0gZGF0YS5mcmFtZShnZW5lID0gdHNzX3dpdGhfbG9vcHMkZW5zZW1ibCwKICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF9jaHIgPSBzZXFuYW1lcyhsb29wc193aXRoX3RzcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGxvb3Bfc3RhcnQgPSBzdGFydChsb29wc193aXRoX3RzcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BfZW5kID0gZW5kKGxvb3BzX3dpdGhfdHNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF93aWR0aCA9IHdpZHRoKGxvb3BzX3dpdGhfdHNzKSkKCiMgSWRlbnRpZnkgdGhlIGxhcmdlc3QgbG9vcCBmb3IgZWFjaCBnZW5lCmxhcmdlc3RfbG9vcHMgPC0gbG9vcF9kYXRhW29yZGVyKGxvb3BfZGF0YSRnZW5lLCAtbG9vcF9kYXRhJGxvb3Bfd2lkdGgpLCBdCmxhcmdlc3RfbG9vcHMgPC0gbGFyZ2VzdF9sb29wc1shZHVwbGljYXRlZChsYXJnZXN0X2xvb3BzJGdlbmUpLCBdCmxhcmdlc3RfbG9vcHMgPC0gbGFyZ2VzdF9sb29wcyAlPiUgZHBseXI6Om11dGF0ZShsb29wSUQgPSBwYXN0ZShsb29wX2NociwgbG9vcF9zdGFydCwgbG9vcF9lbmQsIHNlcCA9ICJfIikpCmxhcmdlc3RfbG9vcHMgPC0gbGFyZ2VzdF9sb29wc1tvcmRlcihsYXJnZXN0X2xvb3BzJGxvb3BfY2hyLCBsYXJnZXN0X2xvb3BzJGxvb3Bfc3RhcnQpLF0Kcm93bmFtZXMobGFyZ2VzdF9sb29wcykgPC0gTlVMTAoKIyBDaGVja2luZyBzbWFsbGVyIGxvb3BzCmFsbExvb3BzR3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGFsbExvb3BzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxbmFtZXMuZmllbGQgPSAiY2hyb20xIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gInN0YXJ0MSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQuZmllbGQgPSAiZW5kMiIpCmxhcmdlc3RMb29wc0dyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShsYXJnZXN0X2xvb3BzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImxvb3BfY2hyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydC5maWVsZCA9ICJsb29wX3N0YXJ0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQuZmllbGQgPSAibG9vcF9lbmQiKQpsYXJnZXN0TG9vcHNHciA8LSBzb3J0KHVuaXF1ZShsYXJnZXN0TG9vcHNHcikpCmNvbXBsZXRlX292ZXJsYXBzIDwtIHN1YnNldEJ5T3ZlcmxhcHMoYWxsTG9vcHNHciwgbGFyZ2VzdExvb3BzR3IsIHR5cGUgPSAid2l0aGluIikKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGNvbXBsZXRlX292ZXJsYXBzLCBsYXJnZXN0TG9vcHNHcikKCgpjb21wbGV0ZU92ZXJsYXBEZiA8LSBhcy5kYXRhLmZyYW1lKGNvbXBsZXRlX292ZXJsYXBzKSAlPiUgZHBseXI6Om11dGF0ZShsb29wSURBbGwgPSBwYXN0ZShzZXFuYW1lcywgc3RhcnQsIGVuZCwgc2VwID0gIl8iKSkKbGFyZ2VzdExvb3BzRGYgPC0gYXMuZGF0YS5mcmFtZShsYXJnZXN0TG9vcHNHcikgJT4lIGRwbHlyOjptdXRhdGUobG9vcElEID0gcGFzdGUoc2VxbmFtZXMsIHN0YXJ0LCBlbmQsIHNlcCA9ICJfIikpCgpsb29wSURwYWlycyA8LSBkYXRhLmZyYW1lKGxvb3BJRCA9IGNvbXBsZXRlT3ZlcmxhcERmJGxvb3BJREFsbFtxdWVyeUhpdHMob3ZlcmxhcHMpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsb29wSUQyID0gbGFyZ2VzdExvb3BzRGYkbG9vcElEW3N1YmplY3RIaXRzKG92ZXJsYXBzKV0pCgphbGxMb29wc0Fubm90YXRlZCA8LSBhbGxMb29wcyAlPiUgZHBseXI6Om11dGF0ZShsb29wSUQgPSBwYXN0ZShjaHJvbTEsIHN0YXJ0MSwgZW5kMiwgc2VwID0gIl8iKSkgJT4lIGRwbHlyOjpsZWZ0X2pvaW4obG9vcElEcGFpcnMsIGJ5ID0gYygibG9vcElEIikpCgp0ZW1wIDwtIGFsbExvb3BzQW5ub3RhdGVkICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1FIiwgIlAtUCIsICJFLUUiKSkgJT4lIGRwbHlyOjptdXRhdGUoaGFzU1MgPSAhaXMubmEobG9vcElEMikpCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihoYXNTUyA9PWdyb3VwMSkgKSRkaWZmX2RUQUdfRE1TTwogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihoYXNTUyA9PWdyb3VwMikgKSRkaWZmX2RUQUdfRE1TTwogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KcHYgPC0gY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsIFRSVUUsIEZBTFNFKSkKZ2dwbG90KHRlbXAsIGFlcyh4ID0gaGFzU1MsIHkgPSBkaWZmX2RUQUdfRE1TTykpICsgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBoYXNTUyksIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gaGFzU1MpLCBmdW4gPSBtZWFuLCAKICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAyLCBmaWxsID0gInJlZCIsIGNvbG9yID0gImJsYWNrIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAsIGxhYmVsID0gcHYsIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpICsKICBnZ3RpdGxlKCJQRS1QRSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKCgojIENvdW50aW5nIGxvb3AgdHlwZXMKYWxsTG9vcHNBbm5vdGF0ZWRGaWx0ZXJlZCA8LSBhbGxMb29wc0Fubm90YXRlZCAlPiUgZHBseXI6OmZpbHRlcighaXMubmEobG9vcElEMikpICU+JQogIGRwbHlyOjpmaWx0ZXIoIShsb29wSUQgPT0gbG9vcElEMikpCnRlbXAgPC0gYWxsTG9vcHNBbm5vdGF0ZWRGaWx0ZXJlZCAlPiUgZHBseXI6OnNlbGVjdChsb29wSUQyLCBBbm5vMikKcmVzdWx0IDwtIHRlbXAgJT4lCiAgZ3JvdXBfYnkobG9vcElEMiwgQW5ubzIpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lCiAgZ3JvdXBfYnkobG9vcElEMikgJT4lCiAgbXV0YXRlKGZyZXF1ZW5jeSA9IGNvdW50IC8gc3VtKGNvdW50KSkgJT4lCiAgYXJyYW5nZShsb29wSUQyLCBBbm5vMikKCnJlc3VsdCA8LSBsYXJnZXN0X2xvb3BzICU+JSBkcGx5cjo6bGVmdF9qb2luKHJlc3VsdCwgYnkgPSBjKCJsb29wSUQiID0gImxvb3BJRDIiKSkKCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCmRhdGEgPC0gdGliYmxlKAogIGdlbmUgPSBjKGdlbmUuZ3JvdXAxLCBnZW5lLmdyb3VwMiksCiAgZ3JvdXAgPSBjKHJlcCgiZ3JvdXAxIiwgbGVuZ3RoKGdlbmUuZ3JvdXAxKSksCiAgICAgICAgICAgIHJlcCgiZ3JvdXAyIiwgbGVuZ3RoKGdlbmUuZ3JvdXAyKSkpCikKCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihyZXN1bHQsIGJ5ID0gYygiZ2VuZSIpKQpkYXRhIDwtIGRhdGEgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkKCmFsbF9hbm5vMiA8LSB1bmlxdWUoZGF0YSRBbm5vMikKCiMgQ2FsY3VsYXRlIGF2ZXJhZ2UgZnJlcXVlbmN5IG9mIEFubm8yIGZvciBlYWNoIGdlbmUgaW4gZWFjaCBncm91cApyZXN1bHQgPC0gZGF0YSAlPiUKICAjIEVuc3VyZSBhbGwgcG9zc2libGUgQW5ubzIgdmFsdWVzIGFyZSBwcmVzZW50IGZvciBlYWNoIGdlbmUgYW5kIGdyb3VwCiAgY29tcGxldGUoZ2VuZSwgQW5ubzIgPSBhbGxfYW5ubzIsIGZpbGwgPSBsaXN0KGZyZXF1ZW5jeSA9IDApKSAlPiUgCiAgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbigKICAgIGdlbmUgJWluJSBnZW5lLmdyb3VwMSB+ICJncm91cDEiLAogICAgZ2VuZSAlaW4lIGdlbmUuZ3JvdXAyIH4gImdyb3VwMiIsCiAgICBUUlVFIH4gTkEKICApKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdyb3VwLCBBbm5vMiwgZnJlcXVlbmN5KQogIAoKZ2dwbG90KHJlc3VsdCwgYWVzKHggPSBBbm5vMiwgZmlsbCA9IGdyb3VwLCB5ID0gZnJlcXVlbmN5KSkgKyBnZW9tX2JveHBsb3QoKQoKYGBgCgoKYGBge3J9CiMgVmlldyByZXN1bHRzCmdncGxvdChsYXJnZXN0X2xvb3BzLCBhZXMoeCA9IGxvb3Bfd2lkdGgpKSArIGdlb21faGlzdG9ncmFtKCkKCgojIyMgQ2hlY2tpbmcgaG93IG1hbnkgZ2VuZXMgZnJvbSBlYWNoIGdyb3VwIGhhcyBlbmNvbXBhc3NpbmcgUy1TCmdlbmUuZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpnZW5lLmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCmRhdGEgPC0gdGliYmxlKAogIGdlbmUgPSBjKGdlbmUuZ3JvdXAxLCBnZW5lLmdyb3VwMiksCiAgZ3JvdXAgPSBjKHJlcCgiZ3JvdXAxIiwgbGVuZ3RoKGdlbmUuZ3JvdXAxKSksCiAgICAgICAgICAgIHJlcCgiZ3JvdXAyIiwgbGVuZ3RoKGdlbmUuZ3JvdXAyKSkpCikKCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihsYXJnZXN0X2xvb3BzLCBieSA9IGMoImdlbmUiKSkKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bXV0YXRlKAogIGhhc1NTID0gaWZlbHNlKGlzLm5hKGxvb3Bfd2lkdGgpLCAiTk8iLCAiWUVTIikKKQoKZGF0YV9zdW1tYXJ5IDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoZ3JvdXApICU+JQogIHN1bW1hcml6ZSgKICAgIHRvdGFsID0gbigpLAogICAgaGFzU1NfeWVzID0gc3VtKGhhc1NTID09ICJZRVMiKSwKICAgIHBlcmNlbnRhZ2VfeWVzID0gKGhhc1NTX3llcyAvIHRvdGFsKSAqIDEwMAogICkKCmdncGxvdChkYXRhX3N1bW1hcnksIGFlcyh4ID0gZ3JvdXAsIHkgPSBwZXJjZW50YWdlX3llcywgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUGVyY2VudGFnZSBvZiBFYWNoIEdyb3VwIHdpdGggaGFzU1MgPSBZRVMiLAogICAgeCA9ICJHcm91cCIsCiAgICB5ID0gIlBlcmNlbnRhZ2UgKCUpIgogICkgKyB5bGltKDAsIDEwMCkgKwogIHRoZW1lX21pbmltYWwoKQoKCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OmZpbHRlcihoYXNTUyA9PSAiWUVTIikKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGxvb3Bfd2lkdGgKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDIpICkkbG9vcF93aWR0aAogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KcHYgPC0gY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsICJncm91cDEiLCAiZ3JvdXAyIikpCgpnZ3Bsb3QodGVtcCwgYWVzKHggPSBncm91cCwgeSA9IGxvb3Bfd2lkdGgpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjUpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwdiwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikKCiMjIyBDb21wYXJpbmcgUk5BIHBlcnR1cmJhdGlvbgoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGMoMSwgNCwgNSkpICU+JQogIGRwbHlyOjptdXRhdGUoaGFzU1MgPSBpZmVsc2UoZW5zZW1ibF9nZW5lX2lkICVpbiUgbGFyZ2VzdF9sb29wcyRnZW5lLCAiaGFzU1MiLCAibm9TUyIpKQoKCmdncGxvdChkaWZmLlJOQSwgYWVzKHggPSBhYnMobG9nMkZvbGRDaGFuZ2UpLCBjb2xvciA9IGhhc1NTKSkgKwogIHN0YXRfZWNkZihzaXplID0gMC40KSArCiAgbGFicygKICAgIHggPSAiQWJzb2x1dGUgbG9nMihmb2xkIGNoYW5nZSkiLAogICAgeSA9ICJDdW11bGF0aXZlIFByb2JhYmlsaXR5IgogICkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMS41KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICMgQ2xlYW4gdGhlbWUKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKQoKCiMjIyBDaGVja2luZyBDaElQIHBlYWsgZGVuc2l0eQpsYXJnZXN0X2xvb3BzR3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGxhcmdlc3RfbG9vcHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImxvb3BfY2hyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQuZmllbGQgPSAibG9vcF9zdGFydCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJsb29wX2VuZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCgojIEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBDaElQLXNlcSBwZWFrcyBhbmQgdGhlIGxhcmdlc3QgbG9vcHMKY2hpcF9vdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMobGFyZ2VzdF9sb29wc0dyLCBwZWFrLkNUQ0YpCgojIENvdW50IHRoZSBudW1iZXIgb2YgQ2hJUC1zZXEgcGVha3MgcGVyIGxvb3AKbG9vcF9wZWFrX2NvdW50cyA8LSB0YWJsZShxdWVyeUhpdHMoY2hpcF9vdmVybGFwcykpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgY291bnRzIGFuZCBsb29wIGRldGFpbHMKbGFyZ2VzdF9sb29wcyRkZW5zaXR5IDwtIDAgICMgSW5pdGlhbGl6ZSBkZW5zaXR5IGNvbHVtbgpsYXJnZXN0X2xvb3BzJGNvdW50IDwtIDAgICAgIyBJbml0aWFsaXplIHBlYWsgY291bnQgY29sdW1uCgojIEFkZCBwZWFrIGNvdW50cyB0byB0aGUgY29ycmVzcG9uZGluZyBsb29wcwpsYXJnZXN0X2xvb3BzW2FzLm51bWVyaWMobmFtZXMobG9vcF9wZWFrX2NvdW50cykpLCAiY291bnQiXSA8LSBhcy5pbnRlZ2VyKGxvb3BfcGVha19jb3VudHMpCgojIENhbGN1bGF0ZSB0aGUgZGVuc2l0eSAocGVha3MgcGVyIGtpbG9iYXNlKQpsYXJnZXN0X2xvb3BzJGRlbnNpdHkgPC0gbGFyZ2VzdF9sb29wcyRjb3VudCAvICgobGFyZ2VzdF9sb29wcyRsb29wX3dpZHRoLTEpIC8gMTAwMCkKCgpkYXRhIDwtIHRpYmJsZSgKICBnZW5lID0gYyhnZW5lLmdyb3VwMSwgZ2VuZS5ncm91cDIpLAogIGdyb3VwID0gYyhyZXAoImdyb3VwMSIsIGxlbmd0aChnZW5lLmdyb3VwMSkpLAogICAgICAgICAgICByZXAoImdyb3VwMiIsIGxlbmd0aChnZW5lLmdyb3VwMikpKQopCgpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4obGFyZ2VzdF9sb29wcywgYnkgPSBjKCJnZW5lIikpCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZSgKICBoYXNTUyA9IGlmZWxzZShpcy5uYShsb29wX3dpZHRoKSwgIk5PIiwgIllFUyIpCikgJT4lIGRwbHlyOjpmaWx0ZXIoaGFzU1MgPT0gIllFUyIpCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkZGVuc2l0eQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRkZW5zaXR5CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKcHYgPC0gY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJncm91cDEiLCAiZ3JvdXAyIikpCgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IGRlbnNpdHkpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgCiAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHB2LCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2d0aXRsZSgiQ1RDRiIpCgoKYGBgCgojIyMgWzMuNDFdIEZpbmRpbmcgbGFyZ2VzdCBjb252ZXJnZW50IGVuY29tcGFzc2luZyBTLVMKIyMjIyBGaWx0ZXJpbmcgY29udmVyZ2VudCBTLVMgbG9vcHMKYGBge3J9Cm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgojIElNUE9SVCBTLVMgTE9PUFMKYWxsTG9vcHMgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5LnRzdiIpKQpzdHJMb29wcyA8LSBhbGxMb29wcyAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlMtUyIpKQp0ZW1wIDwtIHN0ckxvb3BzICU+JSBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgMywgNSwgNikpICAjIEFzc3VtaW5nIGNvbHVtbnMgaW5jbHVkZSBhbmNob3IgcG9zaXRpb25zCmNvbG5hbWVzKHRlbXApIDwtIGMoImNocm9tIiwgInN0YXJ0MSIsICJlbmQxIiwgInN0YXJ0MiIsICJlbmQyIikKc3RyTG9vcHNHcjEgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKAogIHRlbXAgJT4lIGRwbHlyOjpzZWxlY3QoY2hyb20sIHN0YXJ0ID0gc3RhcnQxLCBlbmQgPSBlbmQxKQopCnN0ckxvb3BzR3IyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSgKICB0ZW1wICU+JSBkcGx5cjo6c2VsZWN0KGNocm9tLCBzdGFydCA9IHN0YXJ0MiwgZW5kID0gZW5kMikKKQoKIyBJTVBPUlQgQ1RDRiBNT1RJRiBBTk5PVEFUSU9OCmN0Y2ZNb3RpZnMgPC0gZnJlYWQoaGVyZShyZWZEaXIsICIzMzI0OF9DVENGXzA3LTcyOV9CcnVjZS00X3BlYWtzLm1lcmdlUGVhay5tb3RpZkFubm90YXRlZC5iZWQiKSkKY29sbmFtZXMoY3RjZk1vdGlmcykgPC0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgIm1vdGlmIikKY3RjZkdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShjdGNmTW90aWZzLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFKQoKIyBBbm5vdGF0ZSBlYWNoIGxvb3AgYW5jaG9yIHdpdGggQ1RDRiBtb3RpZnMKYW5jaG9yMV93aXRoX2N0Y2YgPC0gZmluZE92ZXJsYXBzKHN0ckxvb3BzR3IxLCBjdGNmR3IpCmFuY2hvcjJfd2l0aF9jdGNmIDwtIGZpbmRPdmVybGFwcyhzdHJMb29wc0dyMiwgY3RjZkdyKQoKIyBHZXQgbW90aWYgaW5mb3JtYXRpb24gZm9yIGFuY2hvcjEgb3ZlcmxhcHMKYW5jaG9yMV9jdGNmX21vdGlmIDwtIHJlcChOQSwgbGVuZ3RoKHN0ckxvb3BzR3IxKSkgICMgSW5pdGlhbGl6ZSBtb3RpZiB2ZWN0b3IKYW5jaG9yMV9jdGNmX21vdGlmW3F1ZXJ5SGl0cyhhbmNob3IxX3dpdGhfY3RjZildIDwtIGN0Y2ZHcltzdWJqZWN0SGl0cyhhbmNob3IxX3dpdGhfY3RjZildJG1vdGlmCgojIEdldCBtb3RpZiBpbmZvcm1hdGlvbiBmb3IgYW5jaG9yMiBvdmVybGFwcwphbmNob3IyX2N0Y2ZfbW90aWYgPC0gcmVwKE5BLCBsZW5ndGgoc3RyTG9vcHNHcjIpKSAgIyBJbml0aWFsaXplIG1vdGlmIHZlY3RvcgphbmNob3IyX2N0Y2ZfbW90aWZbcXVlcnlIaXRzKGFuY2hvcjJfd2l0aF9jdGNmKV0gPC0gY3RjZkdyW3N1YmplY3RIaXRzKGFuY2hvcjJfd2l0aF9jdGNmKV0kbW90aWYKCiMgQWRkIG1vdGlmIGluZm9ybWF0aW9uIHRvIHN0ckxvb3BzCnN0ckxvb3BzIDwtIHN0ckxvb3BzICU+JQogIG11dGF0ZSgKICAgIGFuY2hvcjFfbW90aWYgPSBhbmNob3IxX2N0Y2ZfbW90aWYsCiAgICBhbmNob3IyX21vdGlmID0gYW5jaG9yMl9jdGNmX21vdGlmCiAgKQoKIyBGaWx0ZXIgZm9yIGNvbnZlcmdlbnQgQ1RDRiBpbnRlcmFjdGlvbnMgKGZvcndhcmQgaW4gYW5jaG9yMSwgcmV2ZXJzZSBpbiBhbmNob3IyKQpjb252ZXJnZW50X2xvb3BzIDwtIHN0ckxvb3BzICU+JQogIGZpbHRlcihhbmNob3IxX21vdGlmID09ICJmd2QiICYgYW5jaG9yMl9tb3RpZiA9PSAicmV2IikgJT4lIGRwbHlyOjpmaWx0ZXIoQW5ubzIgJWluJSBjKCJTLVMiKSkKYGBgCgojIyMjIFByb2Nlc3NpbmcKYGBge3J9CiMgRXh0cmFjdCBsb29wIGJvdW5kYXJ5IGZyb20gbGVmdCB0byByaWdodAp0ZW1wIDwtIGNvbnZlcmdlbnRfbG9vcHMgJT4lIGRwbHlyOjpzZWxlY3QoYygxLCAyLCA2KSkKY29sbmFtZXModGVtcCkgPC0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIikKc3RyTG9vcHNHciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodGVtcCkKCiMgSU1QT1JUIFRTUwpmbGFua1NpemUgPC0gMTAKZ2VuZS50YiA8LSBmcmVhZChoZXJlKHJlZkRpciwgIm1tMTBfR1JDbTM4LnA2X2dlbmVfc29ydGVkLmJlZCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKFRTUyA9IGlmZWxzZShWNCA9PSAiKyIsIFYyLCBWMyksCiAgICAgICAgICAgICAgICBUU1NzdGFydCA9IFRTUyAtIGZsYW5rU2l6ZSwKICAgICAgICAgICAgICAgIFRTU2VuZCA9IFRTUyArIGZsYW5rU2l6ZSkgJT4lCiAgZHBseXI6OnNlbGVjdChWMSwgVFNTc3RhcnQsIFRTU2VuZCwgVjYsIFY1KQpjb2xuYW1lcyhnZW5lLnRiKSA8LSBjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAiZW5zZW1ibCIsICJnZW5lIikKZ2VuZUdyIDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShnZW5lLnRiLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFKQoKCiMgRmluZCBvdmVybGFwcyBiZXR3ZWVuIGxvb3BzIGFuZCBUU1MKb3ZlcmxhcHMgPC0gZmluZE92ZXJsYXBzKGdlbmVHciwgc3RyTG9vcHNHcikKCiMgQW5ub3RhdGUgb3ZlcmxhcHMKdHNzX3dpdGhfbG9vcHMgPC0gZ2VuZUdyW3F1ZXJ5SGl0cyhvdmVybGFwcyldCmxvb3BzX3dpdGhfdHNzIDwtIHN0ckxvb3BzR3Jbc3ViamVjdEhpdHMob3ZlcmxhcHMpXQoKIyBDb21iaW5lIGludG8gYSBkYXRhIGZyYW1lIGZvciBwcm9jZXNzaW5nCmxvb3BfZGF0YSA8LSBkYXRhLmZyYW1lKGdlbmUgPSB0c3Nfd2l0aF9sb29wcyRlbnNlbWJsLAogICAgICAgICAgICAgICAgICAgICAgICBsb29wX2NociA9IHNlcW5hbWVzKGxvb3BzX3dpdGhfdHNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF9zdGFydCA9IHN0YXJ0KGxvb3BzX3dpdGhfdHNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF9lbmQgPSBlbmQobG9vcHNfd2l0aF90c3MpLAogICAgICAgICAgICAgICAgICAgICAgICBsb29wX3dpZHRoID0gd2lkdGgobG9vcHNfd2l0aF90c3MpKQoKIyBJZGVudGlmeSB0aGUgbGFyZ2VzdCBsb29wIGZvciBlYWNoIGdlbmUKbGFyZ2VzdF9sb29wcyA8LSBsb29wX2RhdGFbb3JkZXIobG9vcF9kYXRhJGdlbmUsIC1sb29wX2RhdGEkbG9vcF93aWR0aCksIF0KbGFyZ2VzdF9sb29wcyA8LSBsYXJnZXN0X2xvb3BzWyFkdXBsaWNhdGVkKGxhcmdlc3RfbG9vcHMkZ2VuZSksIF0KbGFyZ2VzdF9sb29wcyA8LSBsYXJnZXN0X2xvb3BzICU+JSBkcGx5cjo6bXV0YXRlKGxvb3BJRCA9IHBhc3RlKGxvb3BfY2hyLCBsb29wX3N0YXJ0LCBsb29wX2VuZCwgc2VwID0gIl8iKSkKbGFyZ2VzdF9sb29wcyA8LSBsYXJnZXN0X2xvb3BzW29yZGVyKGxhcmdlc3RfbG9vcHMkbG9vcF9jaHIsIGxhcmdlc3RfbG9vcHMkbG9vcF9zdGFydCksXQpyb3duYW1lcyhsYXJnZXN0X2xvb3BzKSA8LSBOVUxMCgojIENoZWNraW5nIHNtYWxsZXIgbG9vcHMKYWxsTG9vcHNHciA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoYWxsTG9vcHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXFuYW1lcy5maWVsZCA9ICJjaHJvbTEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQuZmllbGQgPSAic3RhcnQxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJlbmQyIikKbGFyZ2VzdExvb3BzR3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGxhcmdlc3RfbG9vcHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxbmFtZXMuZmllbGQgPSAibG9vcF9jaHIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gImxvb3Bfc3RhcnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJsb29wX2VuZCIpCmxhcmdlc3RMb29wc0dyIDwtIHNvcnQodW5pcXVlKGxhcmdlc3RMb29wc0dyKSkKY29tcGxldGVfb3ZlcmxhcHMgPC0gc3Vic2V0QnlPdmVybGFwcyhhbGxMb29wc0dyLCBsYXJnZXN0TG9vcHNHciwgdHlwZSA9ICJ3aXRoaW4iKQpvdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMoY29tcGxldGVfb3ZlcmxhcHMsIGxhcmdlc3RMb29wc0dyKQoKCmNvbXBsZXRlT3ZlcmxhcERmIDwtIGFzLmRhdGEuZnJhbWUoY29tcGxldGVfb3ZlcmxhcHMpICU+JSBkcGx5cjo6bXV0YXRlKGxvb3BJREFsbCA9IHBhc3RlKHNlcW5hbWVzLCBzdGFydCwgZW5kLCBzZXAgPSAiXyIpKQpsYXJnZXN0TG9vcHNEZiA8LSBhcy5kYXRhLmZyYW1lKGxhcmdlc3RMb29wc0dyKSAlPiUgZHBseXI6Om11dGF0ZShsb29wSUQgPSBwYXN0ZShzZXFuYW1lcywgc3RhcnQsIGVuZCwgc2VwID0gIl8iKSkKCmxvb3BJRHBhaXJzIDwtIGRhdGEuZnJhbWUobG9vcElEID0gY29tcGxldGVPdmVybGFwRGYkbG9vcElEQWxsW3F1ZXJ5SGl0cyhvdmVybGFwcyldLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxvb3BJRDIgPSBsYXJnZXN0TG9vcHNEZiRsb29wSURbc3ViamVjdEhpdHMob3ZlcmxhcHMpXSkKCiMgYWxsTG9vcHNBbm5vdGF0ZWQgPC0gYWxsTG9vcHMgJT4lIGRwbHlyOjptdXRhdGUobG9vcElEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIGVuZDIsIHNlcCA9ICJfIikpICU+JSBkcGx5cjo6bGVmdF9qb2luKGxvb3BJRHBhaXJzLCBieSA9IGMoImxvb3BJRCIpKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZGlmZkN1dG9mZiA8LSAwLjIKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IGRpZmZDdXRvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0xpc3QgPSBjKCJQLVAiLCAiUC1FIiwgIlAtUyIsICJQLVgiKSkgJT4lIHVubmVzdChnZW5lKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvb3BJRCA9IHBhc3RlKGNocm9tMSwgc3RhcnQxLCBlbmQyLCBzZXAgPSAiXyIpKQp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmxlZnRfam9pbihsb29wSURwYWlycywgYnkgPSBjKCJsb29wSUQiKSkKdGVtcDIgPC0gdGVtcCAlPiUgZHBseXI6OnNlbGVjdChnZW5lLCBsb29wSUQyKSAlPiUKICBncm91cF9ieShnZW5lKSAlPiUgICAgICAgICAgICAgICMgR3JvdXAgZGF0YSBieSB0aGUgJ2dlbmUnIGNvbHVtbgogIHN1bW1hcml6ZShnZW5lSGFzU1MgPSAhYWxsKGlzLm5hKGxvb3BJRDIpKSkgICMgQ2hlY2sgaWYgYWxsIGxvb3BJRDIgdmFsdWVzIGZvciBlYWNoIGdlbmUgYXJlIE5BCnRlbXAgPC0gdGVtcCAlPiUgbGVmdF9qb2luKHRlbXAyLCBieSA9IGMoImdlbmUiKSkKZGF0YS5hbGwgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGlmZWxzZSghZ2VuZUhhc1NTLCAiTm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGlzLm5hKGxvb3BJRDIpLCAiT3V0c2lkZSIsICJXaXRoaW4iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gc3RhcnQyIC0gc3RhcnQxKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpvdXRmaWxlIDwtIGRhdGEuYWxsICU+JSBkcGx5cjo6c2VsZWN0KGxvb3BJRDIsIGdlbmUpICU+JSBkcGx5cjo6ZmlsdGVyKCFpcy5uYShsb29wSUQyKSkgJT4lCiAgc2VwYXJhdGUobG9vcElEMiwgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIpLCBzZXAgPSAiXyIsIGNvbnZlcnQgPSBUUlVFKQojIGZ3cml0ZShvdXRmaWxlLCBoZXJlKGNvbnNlbnN1c0RpciwgImNvbnZlcmdlbnRfc3NfZG9tYWluLmJlZCIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKYGBgCgojIyMjIFBsb3R0aW5nCmBgYHtyfQpkYXRhIDwtIGRhdGEuYWxsICU+JSBkcGx5cjo6ZmlsdGVyKEFubm8yICVpbiUgYygiUC1FIikpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoY2hyb20xLCBzdGFydDEsIGVuZDEsIGNocm9tMiwgc3RhcnQyLCBlbmQyLCBncm91cCkgJT4lIGRpc3RpbmN0KCkKCnRlbXAxIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIk5vIikgJT4lIGRwbHlyOjpzZWxlY3QoLWdyb3VwKQpmd3JpdGUodGVtcDEsIGhlcmUoY29uc2Vuc3VzRGlyLCAiaW5zdWxhdGVkX2RvbWFpbl9zc19uby5iZWRwZSIpLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSkKdGVtcDIgPC0gdGVtcCAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiV2l0aGluIikgJT4lIGRwbHlyOjpzZWxlY3QoLWdyb3VwKQpmd3JpdGUodGVtcDIsIGhlcmUoY29uc2Vuc3VzRGlyLCAiaW5zdWxhdGVkX2RvbWFpbl9zc193aXRoaW4uYmVkcGUiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCnRlbXAzIDwtIHRlbXAgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIk91dHNpZGUiKSAlPiUgZHBseXI6OnNlbGVjdCgtZ3JvdXApCmZ3cml0ZSh0ZW1wMywgaGVyZShjb25zZW5zdXNEaXIsICJpbnN1bGF0ZWRfZG9tYWluX3NzX291dHNpZGUuYmVkcGUiKSwgc2VwID0gIlx0IiwgY29sLm5hbWVzID0gRkFMU0UpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoaWQsIGdyb3VwLCBzaXplKSAlPiUgZGlzdGluY3QoKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRzaXplCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJHNpemUKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9Cgpjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgIk5vIiwgIldpdGhpbiIpKQpjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgIk5vIiwgIk91dHNpZGUiKSkKY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsICJPdXRzaWRlIiwgIldpdGhpbiIpKQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBzaXplLCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fdmlvbGluKGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0qIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLCBhbHBoYSA9IC40LCAsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9rYl9tYikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM3Nzc3NzciLCAiI0YyOEUyQyIsICIjRjI4RTJDIikpICsKICBzdGF0X3N1bW1hcnkoCiAgICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAwLjUsCiAgICAgIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJibGFjayIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoLjMpCiAgKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLCAgICAKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApICtsYWJzKHkgPSAiTG9vcCBzaXplIikKCmZpbGVOYW1lIDwtIHBhc3RlMCgiaW5zdWxhdGlvbkJvdW5kYXJ5X3NpemVfY29udlNTX1BFIikKd2lkdGggPC0zMyptbVRvSW5jaApoZWlnaHQgPC0gMzUqbW1Ub0luY2gKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRkaWZmX2RUQUdfRE1TTwogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRkaWZmX2RUQUdfRE1TTwogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnRlbXAgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChncm91cCwgaWQsIGRpZmZfZFRBR19ETVNPKSAlPiUgZGlzdGluY3QoKQoKY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsICJObyIsICJXaXRoaW4iKSkKY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsICJObyIsICJPdXRzaWRlIikpCmNvbnZQdmFsdWUoZ2V0UHZhbFdpbGNveCh0ZW1wLCAiT3V0c2lkZSIsICJXaXRoaW4iKSkKCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gZ3JvdXAsIHkgPSBkaWZmX2RUQUdfRE1TTywgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX3Zpb2xpbihsaW5ld2lkdGggPSBsaW5lTWVkaXVtICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIGFscGhhID0gLjQsICwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEsICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKyAgIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzc3Nzc3NyIsICIjRjI4RTJDIiwgIiNGMjhFMkMiKSkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICApICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksICAgIAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgK2xhYnMoeSA9ICLOlCBsb29wIHNjb3JlIikgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgYWxwaGEgPSAxLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLTAuMiwKICAgICAgICAgICAgIGFscGhhID0gMC41LCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICAgICAgICAgbGluZWVuZCA9ICJzcXVhcmUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjgsIDAuNSkpCiAgICAKZmlsZU5hbWUgPC0gcGFzdGUwKCJpbnN1bGF0aW9uQm91bmRhcnlfZGVsdGFfY29udlNTX3BlIikKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkgIAoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgCgptaW5WYWx1ZSA8LSAtNApvYnNleHAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMCgibG9vcFNjb3JlX2NvbnNfb2JzZXhwLnRzdiIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb2dfb2JzZXhwX0RNU08gPSBpZl9lbHNlKG9ic2V4cF9ETVNPID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9ETVNPKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RUQUcgPSBpZl9lbHNlKG9ic2V4cF9kVEFHID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9kVEFHKSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX0E0ODUgPSBpZl9lbHNlKG9ic2V4cF9BNDg1ID09IDAsIG1pblZhbHVlLCBsb2cyKG9ic2V4cF9BNDg1KSksCiAgICAgICAgICAgICAgICBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPID0gbG9nX29ic2V4cF9kVEFHIC0gbG9nX29ic2V4cF9ETVNPLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX0E0ODVfRE1TTyA9IGxvZ19vYnNleHBfQTQ4NSAtIGxvZ19vYnNleHBfRE1TTykKCmRhdGEyIDwtIGRhdGEgJT4lIGxlZnRfam9pbihvYnNleHAsIGJ5ID0gYygiaWQiKSkKCnRlbXAgPC0gZGF0YTIgJT4lIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIGlkLCBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPKSAlPiUgZGlzdGluY3QoKQoKCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJGxvZ19vYnNleHBfZGlmZl9kVEFHX0RNU08KICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9Cgpjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgIk5vIiwgIldpdGhpbiIpKQpjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgIk5vIiwgIk91dHNpZGUiKSkKY29udlB2YWx1ZShnZXRQdmFsV2lsY294KHRlbXAsICJPdXRzaWRlIiwgIldpdGhpbiIpKQoKCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPLCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fdmlvbGluKGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0qIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLCBhbHBoYSA9IC40LCAsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BLCAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzc3Nzc3NyIsICIjRjI4RTJDIiwgIiNGMjhFMkMiKSkgKwogIAogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICApICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksICAgIAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGFuZ2xlID0gNDUsICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyA0NSBkZWdyZWVzCiAgICAgIGhqdXN0ID0gMSwgICAgICAgIyBBZGp1c3QgaG9yaXpvbnRhbCBqdXN0aWZpY2F0aW9uCiAgICAgIHZqdXN0ID0gMSAgICAgICAgIyBBZGp1c3QgdmVydGljYWwganVzdGlmaWNhdGlvbgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICkgK2xhYnMoeSA9ICJsb2cyKGZjIG9mIG9icy9leHApIikgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgYWxwaGEgPSAxLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0yLCAyKSkKICAgIHdpZHRoIDwtMzAqbW1Ub0luY2gKaGVpZ2h0IDwtIDM1Km1tVG9JbmNoCmZpbGVOYW1lIDwtIHBhc3RlMCgiaW5zdWxhdGlvbkJvdW5kYXJ5X29ic2V4cF9jb252U1NfcGUiKQpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKSAgCgoKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpkYXRhIDwtIGRhdGEuYWxsCmdlbmUud2l0aGluQm91bmRhcnkgPC0gdW5pcXVlKChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJXaXRoaW4iKSkkZ2VuZSkKZ2VuZS5vdXRzaWRlQm91bmRhcnkgPC0gdW5pcXVlKChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJPdXRzaWRlIikpJGdlbmUpCmdlbmUubm9Cb3VuZGFyeSA8LSB1bmlxdWUoKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIk5vIikpJGdlbmUpCgpnZW5lLndCb3VuZGFyeSA8LSB1bmlxdWUoYyhnZW5lLndpdGhpbkJvdW5kYXJ5LCBnZW5lLm91dHNpZGVCb3VuZGFyeSkpCgpnZW5lLmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ2VuZS5ncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpwcmludCgicGVyYyBvZiBnZW5lIHdpdGggbG9vcCB3aXRoaW4gQm91bmRhcnkiKQpzdW0oZ2VuZS5ncm91cDEgJWluJSBnZW5lLndpdGhpbkJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApzdW0oZ2VuZS5ncm91cDIgJWluJSBnZW5lLndpdGhpbkJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDIpKjEwMAoKcHJpbnQoInBlcmMgb2YgZ2VuZSB3aXRoIGxvb3Agb3V0c2lkZSBCb3VuZGFyeSIpCnN1bShnZW5lLmdyb3VwMSAlaW4lIGdlbmUub3V0c2lkZUJvdW5kYXJ5KS9sZW5ndGgoZ2VuZS5ncm91cDEpKjEwMApzdW0oZ2VuZS5ncm91cDIgJWluJSBnZW5lLm91dHNpZGVCb3VuZGFyeSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCnByaW50KCJwZXJjIG9mIGdlbmUgd2l0aCBsb29wIHdpdGggbm8gQm91bmRhcnkiKQpzdW0oZ2VuZS5ncm91cDEgJWluJSBnZW5lLm5vQm91bmRhcnkpL2xlbmd0aChnZW5lLmdyb3VwMSkqMTAwCnN1bShnZW5lLmdyb3VwMiAlaW4lIGdlbmUubm9Cb3VuZGFyeSkvbGVuZ3RoKGdlbmUuZ3JvdXAyKSoxMDAKCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBsb2cyRm9sZENoYW5nZSwgc2hyaW5rZWRfbG9nMkZDLCBwYWRqLCBleHRlcm5hbF9nZW5lX25hbWUpICU+JQogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oCiAgICBlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lLndCb3VuZGFyeSB+ICJ3aXRoaW5Cb3VuZGFyeSIsCiAgICBlbnNlbWJsX2dlbmVfaWQgJWluJSBnZW5lLm5vQm91bmRhcnkgfiAibm9Cb3VuZGFyeSIsCiAgICBUUlVFIH4gTkEKICApKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShncm91cCkpICU+JQogIGRwbHlyOjptdXRhdGUoYWJzTG9nMkZDID0gYWJzKGxvZzJGb2xkQ2hhbmdlKSkKa3NfcmVzdWx0IDwtIGtzLnRlc3QoCiAgZGlmZi5STkEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIndpdGhpbkJvdW5kYXJ5IikgJT4lIHB1bGwoYWJzTG9nMkZDKSwKICBkaWZmLlJOQSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAibm9Cb3VuZGFyeSIpICU+JSBwdWxsKGFic0xvZzJGQykKKQoKZ2dwbG90KGRpZmYuUk5BLCBhZXMoeCA9IGdyb3VwLCB5ID0gbG9nMkZvbGRDaGFuZ2UpKSArIGdlb21fdmlvbGluKCkgKyBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEpCgojIGdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewojICAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAxKSApJGFic0xvZzJGQwojICAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJGFic0xvZzJGQwojICAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQojICAgcmV0dXJuKHdpbCRwLnZhbHVlKQojIH0KIyBjb252UHZhbHVlKGdldFB2YWxXaWxjb3goZGlmZi5STkEsICJ3aXRoQm91bmRhcnkiLCAibm9Cb3VuZGFyeSIpKQojIAoKIyBDcmVhdGUgdGhlIENERiBwbG90CnAgPC0gZ2dwbG90KGRpZmYuUk5BLCBhZXMoeCA9IGFic0xvZzJGQywgY29sb3IgPSBncm91cCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gKGMoIiM3Nzc3NzciLCAiI0YyOEUyQyIpKSkgKwoKc3RhdF9lY2RmKHNpemUgPSAwLjQsIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiAgKSArICMgVXNlIHN0YXRfZWNkZiB0byBwbG90IHRoZSBlbXBpcmljYWwgQ0RGCiAgbGFicygKICAgIHggPSAiQWJzLiBsb2cyKGZvbGQgY2hhbmdlKSIsCiAgICB5ID0gIkN1bXVsYXRpdmUgUHJvYmFiaWxpdHkiCiAgKSArIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAxKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICMgQ2xlYW4gdGhlbWUKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJsb2cyRkNfY2RmX2luc3VsYXRpb25Cb3VuZGFyeV9jb252U1NfcGUiKQp3aWR0aCA8LSAzMyptbVRvSW5jaApoZWlnaHQgPC0zMyptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCgpgYGB7cn0KdGVtcCA8LSBhbGxMb29wc0Fubm90YXRlZCAlPiUgZHBseXI6OmZpbHRlcihBbm5vMiAlaW4lIGMoIlAtRSIpKSAlPiUgZHBseXI6Om11dGF0ZShoYXNTUyA9ICFpcy5uYShsb29wSUQyKSkKZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGhhc1NTID09Z3JvdXAxKSApJGRpZmZfZFRBR19ETVNPCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGhhc1NTID09Z3JvdXAyKSApJGRpZmZfZFRBR19ETVNPCiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQpwdiA8LSBjb252UHZhbHVlKGdldFB2YWxXaWxjb3godGVtcCwgVFJVRSwgRkFMU0UpKQpnZ3Bsb3QodGVtcCwgYWVzKHggPSBoYXNTUywgeSA9IGRpZmZfZFRBR19ETVNPKSkgKyBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IGhhc1NTKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBoYXNTUyksIGZ1biA9IG1lYW4sIAogICAgICAgICAgICAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIsIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxLCB5ID0gMCwgbGFiZWwgPSBwdiwgc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIikgKwogIGdndGl0bGUoIlBFIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKQoKCgoKIyBDb3VudGluZyBsb29wIHR5cGVzCmFsbExvb3BzQW5ub3RhdGVkRmlsdGVyZWQgPC0gYWxsTG9vcHNBbm5vdGF0ZWQgJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGxvb3BJRDIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCEobG9vcElEID09IGxvb3BJRDIpKQp0ZW1wIDwtIGFsbExvb3BzQW5ub3RhdGVkRmlsdGVyZWQgJT4lIGRwbHlyOjpzZWxlY3QobG9vcElEMiwgQW5ubzIpCnJlc3VsdCA8LSB0ZW1wICU+JQogIGdyb3VwX2J5KGxvb3BJRDIsIEFubm8yKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JQogIGdyb3VwX2J5KGxvb3BJRDIpICU+JQogIG11dGF0ZShmcmVxdWVuY3kgPSBjb3VudCAvIHN1bShjb3VudCkpICU+JQogIGFycmFuZ2UobG9vcElEMiwgQW5ubzIpCgpyZXN1bHQgPC0gbGFyZ2VzdF9sb29wcyAlPiUgZHBseXI6OmxlZnRfam9pbihyZXN1bHQsIGJ5ID0gYygibG9vcElEIiA9ICJsb29wSUQyIikpCgpnZW5lLmdyb3VwMSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDEudHN2IikpJGdlbmUKZ2VuZS5ncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgpkYXRhIDwtIHRpYmJsZSgKICBnZW5lID0gYyhnZW5lLmdyb3VwMSwgZ2VuZS5ncm91cDIpLAogIGdyb3VwID0gYyhyZXAoImdyb3VwMSIsIGxlbmd0aChnZW5lLmdyb3VwMSkpLAogICAgICAgICAgICByZXAoImdyb3VwMiIsIGxlbmd0aChnZW5lLmdyb3VwMikpKQopCgpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4ocmVzdWx0LCBieSA9IGMoImdlbmUiKSkKZGF0YSA8LSBkYXRhICU+JSBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpCgphbGxfYW5ubzIgPC0gdW5pcXVlKGRhdGEkQW5ubzIpCgojIENhbGN1bGF0ZSBhdmVyYWdlIGZyZXF1ZW5jeSBvZiBBbm5vMiBmb3IgZWFjaCBnZW5lIGluIGVhY2ggZ3JvdXAKcmVzdWx0IDwtIGRhdGEgJT4lCiAgIyBFbnN1cmUgYWxsIHBvc3NpYmxlIEFubm8yIHZhbHVlcyBhcmUgcHJlc2VudCBmb3IgZWFjaCBnZW5lIGFuZCBncm91cAogIGNvbXBsZXRlKGdlbmUsIEFubm8yID0gYWxsX2Fubm8yLCBmaWxsID0gbGlzdChmcmVxdWVuY3kgPSAwKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oCiAgICBnZW5lICVpbiUgZ2VuZS5ncm91cDEgfiAiZ3JvdXAxIiwKICAgIGdlbmUgJWluJSBnZW5lLmdyb3VwMiB+ICJncm91cDIiLAogICAgVFJVRSB+IE5BCiAgKSkgJT4lCiAgZHBseXI6OnNlbGVjdChncm91cCwgQW5ubzIsIGZyZXF1ZW5jeSkKICAKCmdncGxvdChyZXN1bHQsIGFlcyh4ID0gQW5ubzIsIGZpbGwgPSBncm91cCwgeSA9IGZyZXF1ZW5jeSkpICsgZ2VvbV9ib3hwbG90KCkKCgoKIyBWaWV3IHJlc3VsdHMKZ2dwbG90KGxhcmdlc3RfbG9vcHMsIGFlcyh4ID0gbG9vcF93aWR0aCkpICsgZ2VvbV9oaXN0b2dyYW0oKQoKCiMjIyBDaGVja2luZyBob3cgbWFueSBnZW5lcyBmcm9tIGVhY2ggZ3JvdXAgaGFzIGVuY29tcGFzc2luZyBTLVMKZ2VuZS5ncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdlbmUuZ3JvdXAyIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMi50c3YiKSkkZ2VuZQoKZGF0YSA8LSB0aWJibGUoCiAgZ2VuZSA9IGMoZ2VuZS5ncm91cDEsIGdlbmUuZ3JvdXAyKSwKICBncm91cCA9IGMocmVwKCJncm91cDEiLCBsZW5ndGgoZ2VuZS5ncm91cDEpKSwKICAgICAgICAgICAgcmVwKCJncm91cDIiLCBsZW5ndGgoZ2VuZS5ncm91cDIpKSkKKQoKZGF0YSA8LSBkYXRhICU+JSBkcGx5cjo6bGVmdF9qb2luKGxhcmdlc3RfbG9vcHMsIGJ5ID0gYygiZ2VuZSIpKQpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjptdXRhdGUoCiAgaGFzU1MgPSBpZmVsc2UoaXMubmEobG9vcF93aWR0aCksICJOTyIsICJZRVMiKQopCgpkYXRhX3N1bW1hcnkgPC0gZGF0YSAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgc3VtbWFyaXplKAogICAgdG90YWwgPSBuKCksCiAgICBoYXNTU195ZXMgPSBzdW0oaGFzU1MgPT0gIllFUyIpLAogICAgcGVyY2VudGFnZV95ZXMgPSAoaGFzU1NfeWVzIC8gdG90YWwpICogMTAwCiAgKQoKZ2dwbG90KGRhdGFfc3VtbWFyeSwgYWVzKHggPSBncm91cCwgeSA9IHBlcmNlbnRhZ2VfeWVzLCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQZXJjZW50YWdlIG9mIEVhY2ggR3JvdXAgd2l0aCBoYXNTUyA9IFlFUyIsCiAgICB4ID0gIkdyb3VwIiwKICAgIHkgPSAiUGVyY2VudGFnZSAoJSkiCiAgKSArIHlsaW0oMCwgMTAwKSArCiAgdGhlbWVfbWluaW1hbCgpCgp0ZW1wIDwtIGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoaGFzU1MgPT0gIllFUyIpCmdldFB2YWxXaWxjb3ggPC0gZnVuY3Rpb24oZGF0YSwgZ3JvdXAxLCBncm91cDIpewogIGRpc3RhbmNlMSA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMSkgKSRsb29wX3dpZHRoCiAgZGlzdGFuY2UyIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09Z3JvdXAyKSApJGxvb3Bfd2lkdGgKICB3aWwgPC0gd2lsY294LnRlc3QoZGlzdGFuY2UxLCBkaXN0YW5jZTIpCiAgcmV0dXJuKHdpbCRwLnZhbHVlKQp9CnB2IDwtIGNvbnZQdmFsdWUoZ2V0UHZhbFdpbGNveCh0ZW1wLCAiZ3JvdXAxIiwgImdyb3VwMiIpKQoKZ2dwbG90KHRlbXAsIGFlcyh4ID0gZ3JvdXAsIHkgPSBsb29wX3dpZHRoKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41KSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAsIGxhYmVsID0gcHYsIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpCgoKIyMjIENvbXBhcmluZyBSTkEgcGVydHVyYmF0aW9uCgpkaWZmLlJOQSA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpzZWxlY3QoYygxLCA0LCA1KSkgJT4lCiAgZHBseXI6Om11dGF0ZShoYXNTUyA9IGlmZWxzZShlbnNlbWJsX2dlbmVfaWQgJWluJSBsYXJnZXN0X2xvb3BzJGdlbmUsICJoYXNTUyIsICJub1NTIikpCgoKZ2dwbG90KGRpZmYuUk5BLCBhZXMoeCA9IGFicyhsb2cyRm9sZENoYW5nZSksIGNvbG9yID0gaGFzU1MpKSArCiAgc3RhdF9lY2RmKHNpemUgPSAwLjQpICsKICBsYWJzKAogICAgeCA9ICJBYnNvbHV0ZSBsb2cyKGZvbGQgY2hhbmdlKSIsCiAgICB5ID0gIkN1bXVsYXRpdmUgUHJvYmFiaWxpdHkiCiAgKSArIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAxLjUpKSArCiAgdGhlbWVfY2xhc3NpYygpICsgIyBDbGVhbiB0aGVtZQogIHRoZW1lKAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgICApCgoKCiMjIyBDaGVja2luZyBDaElQIHBlYWsgZGVuc2l0eQpsYXJnZXN0X2xvb3BzR3IgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGxhcmdlc3RfbG9vcHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImxvb3BfY2hyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQuZmllbGQgPSAibG9vcF9zdGFydCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJsb29wX2VuZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCgojIEZpbmQgb3ZlcmxhcHMgYmV0d2VlbiBDaElQLXNlcSBwZWFrcyBhbmQgdGhlIGxhcmdlc3QgbG9vcHMKY2hpcF9vdmVybGFwcyA8LSBmaW5kT3ZlcmxhcHMobGFyZ2VzdF9sb29wc0dyLCBwZWFrLkgzSzRtZTMpCgojIENvdW50IHRoZSBudW1iZXIgb2YgQ2hJUC1zZXEgcGVha3MgcGVyIGxvb3AKbG9vcF9wZWFrX2NvdW50cyA8LSB0YWJsZShxdWVyeUhpdHMoY2hpcF9vdmVybGFwcykpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgY291bnRzIGFuZCBsb29wIGRldGFpbHMKbGFyZ2VzdF9sb29wcyRkZW5zaXR5IDwtIDAgICMgSW5pdGlhbGl6ZSBkZW5zaXR5IGNvbHVtbgpsYXJnZXN0X2xvb3BzJGNvdW50IDwtIDAgICAgIyBJbml0aWFsaXplIHBlYWsgY291bnQgY29sdW1uCgojIEFkZCBwZWFrIGNvdW50cyB0byB0aGUgY29ycmVzcG9uZGluZyBsb29wcwpsYXJnZXN0X2xvb3BzW2FzLm51bWVyaWMobmFtZXMobG9vcF9wZWFrX2NvdW50cykpLCAiY291bnQiXSA8LSBhcy5pbnRlZ2VyKGxvb3BfcGVha19jb3VudHMpCgojIENhbGN1bGF0ZSB0aGUgZGVuc2l0eSAocGVha3MgcGVyIGtpbG9iYXNlKQpsYXJnZXN0X2xvb3BzJGRlbnNpdHkgPC0gbGFyZ2VzdF9sb29wcyRjb3VudCAvICgobGFyZ2VzdF9sb29wcyRsb29wX3dpZHRoLTEpIC8gMTAwMCkKCgpkYXRhIDwtIHRpYmJsZSgKICBnZW5lID0gYyhnZW5lLmdyb3VwMSwgZ2VuZS5ncm91cDIpLAogIGdyb3VwID0gYyhyZXAoImdyb3VwMSIsIGxlbmd0aChnZW5lLmdyb3VwMSkpLAogICAgICAgICAgICByZXAoImdyb3VwMiIsIGxlbmd0aChnZW5lLmdyb3VwMikpKQopCgpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpsZWZ0X2pvaW4obGFyZ2VzdF9sb29wcywgYnkgPSBjKCJnZW5lIikpCmRhdGEgPC0gZGF0YSAlPiUgZHBseXI6Om11dGF0ZSgKICBoYXNTUyA9IGlmZWxzZShpcy5uYShsb29wX3dpZHRoKSwgIk5PIiwgIllFUyIpCikgJT4lIGRwbHlyOjpmaWx0ZXIoaGFzU1MgPT0gIllFUyIpCgpnZXRQdmFsV2lsY294IDwtIGZ1bmN0aW9uKGRhdGEsIGdyb3VwMSwgZ3JvdXAyKXsKICBkaXN0YW5jZTEgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT1ncm91cDEpICkkZGVuc2l0eQogIGRpc3RhbmNlMiA8LSAoZGF0YSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PWdyb3VwMikgKSRkZW5zaXR5CiAgd2lsIDwtIHdpbGNveC50ZXN0KGRpc3RhbmNlMSwgZGlzdGFuY2UyKQogIHJldHVybih3aWwkcC52YWx1ZSkKfQoKcHYgPC0gY29udlB2YWx1ZShnZXRQdmFsV2lsY294KGRhdGEsICJncm91cDEiLCAiZ3JvdXAyIikpCgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBncm91cCwgeSA9IGRlbnNpdHkpKSArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZ3JvdXApLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwgCiAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMiwgZmlsbCA9ICJyZWQiLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHB2LCBzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2d0aXRsZSgiSDNLNG1lMyIpCgoKYGBgCgojIyMgWzMuNDJdIENvbXBhcmluZyB0byBSZWcgbG9vcHMgdG8gQTQ4NQpgYGB7cn0KbmFtZSA8LSAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeSIKIyBVUCBsb29wCmxvb3AudXAgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5X3BlLXBlX2RUQUd2c0RNU09fVVBfZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvb3BJRCA9IHBhc3RlKFYxLCBWMiwgVjYsIHNlcCA9ICJfIikpCiMgTk8gbG9vcApsb29wLm5vIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX05PX2RpZmYwLjIuYmVkcGUiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShsb29wSUQgPSBwYXN0ZShWMSwgVjIsIFY2LCBzZXAgPSAiXyIpKQojIFVQIE5PCmxvb3AudXBubyA8LSBiaW5kX3Jvd3MobG9vcC51cCwgbG9vcC5ubykKIyBET1dOIGxvb3AKbG9vcC5kb3duIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCAiY2hyb21vX2NvbnNfYW5ub0hpZXJhcmNoeV9wZS1wZV9kVEFHdnNETVNPX0RPV05fZGlmZjAuMi5iZWRwZSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvb3BJRCA9IHBhc3RlKFYxLCBWMiwgVjYsIHNlcCA9ICJfIikpCgoKYWxsTG9vcHMgPC0gZnJlYWQoaGVyZShjb25zZW5zdXNEaXIsICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5LnRzdiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxvb3BJRCA9IHBhc3RlKGNocm9tMSwgc3RhcnQxLCBlbmQyLCBzZXAgPSAiXyIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKAogICAgbG9vcElEICVpbiUgbG9vcC51cG5vJGxvb3BJRCB+ICJVUCZOTyIsCiAgICBsb29wSUQgJWluJSBsb29wLmRvd24kbG9vcElEIH4gIkRPV04iLAogICAgVFJVRSB+IE5BCiAgKSkgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoZ3JvdXApKQoKbWluVmFsdWUgPC0gLTQKb2JzZXhwIDwtIGZyZWFkKGhlcmUoY29uc2Vuc3VzRGlyLCBwYXN0ZTAoImxvb3BTY29yZV9jb25zX29ic2V4cC50c3YiKSkpICU+JQogIGRwbHlyOjptdXRhdGUobG9nX29ic2V4cF9ETVNPID0gaWZfZWxzZShvYnNleHBfRE1TTyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfRE1TTykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kVEFHID0gaWZfZWxzZShvYnNleHBfZFRBRyA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfZFRBRykpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9BNDg1ID0gaWZfZWxzZShvYnNleHBfQTQ4NSA9PSAwLCBtaW5WYWx1ZSwgbG9nMihvYnNleHBfQTQ4NSkpLAogICAgICAgICAgICAgICAgbG9nX29ic2V4cF9kaWZmX2RUQUdfRE1TTyA9IGxvZ19vYnNleHBfZFRBRyAtIGxvZ19vYnNleHBfRE1TTywKICAgICAgICAgICAgICAgIGxvZ19vYnNleHBfZGlmZl9BNDg1X0RNU08gPSBsb2dfb2JzZXhwX0E0ODUgLSBsb2dfb2JzZXhwX0RNU08pCgphbGxMb29wcyA8LSBhbGxMb29wcyAlPiUgbGVmdF9qb2luKG9ic2V4cCwgYnkgPSBjKCJpZCIpKQphbGxMb29wcyRncm91cCA8LSBmYWN0b3IoYWxsTG9vcHMkZ3JvdXAsIGxldmVscyA9IGMoIlVQJk5PIiwgIkRPV04iKSkKCgojIyMgUGxvdHRpbmcKcDEgPC0gZ2dwbG90KGFsbExvb3BzLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlmZl9BNDg1X0RNU08sIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV92aW9saW4obGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIGFscGhhID0gLjQsICwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5NTAiLCAiZ3JleTUwIikpICsKCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLCAgICAKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApICtsYWJzKHkgPSAizpQgbG9vcCBzY29yZSIpICArICAgIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsCiAgICAgICAgICAgICBhbHBoYSA9IDEsCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtMC4yLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuNSwgMC41KSkKICAgIAoKIyMjIwpwMiA8LSBnZ3Bsb3QoYWxsTG9vcHMsIGFlcyh4ID0gZ3JvdXAsIHkgPSBsb2dfb2JzZXhwX2RpZmZfQTQ4NV9ETVNPLCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fdmlvbGluKGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLCBhbHBoYSA9IC40LCAsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEsICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKyAKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sCiAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJibGFjayIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoLjMpCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleTUwIiwgImdyZXk1MCIpKSArCgogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwgICAgCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgYW5nbGUgPSA0NSwgICAgICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIDQ1IGRlZ3JlZXMKICAgICAgaGp1c3QgPSAxLCAgICAgICAjIEFkanVzdCBob3Jpem9udGFsIGp1c3RpZmljYXRpb24KICAgICAgdmp1c3QgPSAxICAgICAgICAjIEFkanVzdCB2ZXJ0aWNhbCBqdXN0aWZpY2F0aW9uCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSArbGFicyh5ID0gImxvZzIoZmMgb2Ygb2JzL2V4cCkiKSAgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgYWxwaGEgPSAxLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0yLCAyKSkKICAKCgojIyMjIyMjIyMjIyMjCgojIyMgUGxvdHRpbmcKcDMgPC0gZ2dwbG90KGFsbExvb3BzLCBhZXMoeCA9IGdyb3VwLCB5ID0gZGlmZl9kVEFHX0RNU08sIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV92aW9saW4obGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsIGFscGhhID0gLjQsICwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjMsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lX2NsYXNzaWMoKSArIAogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhncm91cCA9IGdyb3VwKSwgZnVuID0gbWVhbiwKICAgIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDIxLCBzaXplID0gMC41LAogICAgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImJsYWNrIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguMykKICApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5NTAiLCAiZ3JleTUwIikpICsKCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZU0sCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplUywKICAgICAgZmFtaWx5ID0gZm9udFR5cGUsCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLCAgICAKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBhbmdsZSA9IDQ1LCAgICAgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgNDUgZGVncmVlcwogICAgICBoanVzdCA9IDEsICAgICAgICMgQWRqdXN0IGhvcml6b250YWwganVzdGlmaWNhdGlvbgogICAgICB2anVzdCA9IDEgICAgICAgICMgQWRqdXN0IHZlcnRpY2FsIGp1c3RpZmljYXRpb24KICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApICtsYWJzKHkgPSAizpQgbG9vcCBzY29yZSIpICArICAgIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsCiAgICAgICAgICAgICBhbHBoYSA9IDEsCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgICAgICAgIGxpbmVlbmQgPSAic3F1YXJlIikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtMC4yLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuNSwgMC41KSkKICAgIAoKIyMjIwpwNCA8LSBnZ3Bsb3QoYWxsTG9vcHMsIGFlcyh4ID0gZ3JvdXAsIHkgPSBsb2dfb2JzZXhwX2RpZmZfZFRBR19ETVNPLCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fdmlvbGluKGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLCBhbHBoYSA9IC40LCAsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiLAogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEsICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKyAKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBncm91cCksIGZ1biA9IG1lYW4sCiAgICBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDAuNSwKICAgIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJibGFjayIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoLjMpCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleTUwIiwgImdyZXk1MCIpKSArCgogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwgICAgCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwKICAgICAgYW5nbGUgPSA0NSwgICAgICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIDQ1IGRlZ3JlZXMKICAgICAgaGp1c3QgPSAxLCAgICAgICAjIEFkanVzdCBob3Jpem9udGFsIGp1c3RpZmljYXRpb24KICAgICAgdmp1c3QgPSAxICAgICAgICAjIEFkanVzdCB2ZXJ0aWNhbCBqdXN0aWZpY2F0aW9uCiAgICApLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLAogICAgICBzaXplID0gbGluZVRoaWNrKm1tVG9MaW5lVW5pdCwKICAgICAgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSArbGFicyh5ID0gImxvZzIoZmMgb2Ygb2JzL2V4cCkiKSAgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgYWxwaGEgPSAxLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgICAgICAgICBsaW5lZW5kID0gInNxdWFyZSIpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0yLCAyKSkKICAKd2lkdGggPC0gcGFuZWxTaXplKDIpKm1tVG9JbmNoCmhlaWdodCA8LSBwYW5lbFNpemUoMS41KSptbVRvSW5jaApmaWxlTmFtZSA8LSBwYXN0ZTAoInJlZ0xvb3BTY29yZWZyb21kVEFHX2RUQUciKQpwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKHAxLCBwMikpCmRldi5vZmYoKQpzdmdsaXRlKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIuc3ZnIikpLCAgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwbG90X2dyaWQocDEsIHAyKSkKZGV2Lm9mZigpICAKCndpZHRoIDwtIHBhbmVsU2l6ZSgyKSptbVRvSW5jaApoZWlnaHQgPC0gcGFuZWxTaXplKDEuNSkqbW1Ub0luY2gKZmlsZU5hbWUgPC0gcGFzdGUwKCJyZWdMb29wU2NvcmVmcm9tZFRBR19BNDg1IikKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChwMywgcDQpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKHAzLCBwNCkpCmRldi5vZmYoKSAgCgp3aWR0aCA8LSBwYW5lbFNpemUoMikqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCmZpbGVOYW1lIDwtIHBhc3RlMCgicmVnTG9vcFNjb3JlZnJvbWRUQUdfbG9vcFNjb3JlIikKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChwMSwgcDMpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKHAxLCBwMykpCmRldi5vZmYoKSAgCgp3aWR0aCA8LSBwYW5lbFNpemUoMikqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjUpKm1tVG9JbmNoCmZpbGVOYW1lIDwtIHBhc3RlMCgicmVnTG9vcFNjb3JlZnJvbWRUQUdfbG9nMmZjIikKcG5nKGhlcmUoZmlnRGlyLCBwYXN0ZTAoZmlsZU5hbWUsICIucG5nIikpLCByZXMgPSA2MDAsIHVuaXQgPSAiaW4iLCBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHBsb3RfZ3JpZChwMiwgcDQpKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocGxvdF9ncmlkKHAyLCBwNCkpCmRldi5vZmYoKSAgCgpgYGAKCiMjIyBbMy40M10gQ2hlY2tpbmcgUkFEMjEgcGVhayBkZW5zaXR5IGF0IGdyb3VwMSBhbmQgZ3JvdXAyIHByb21vdGVyCmBgYHtyfQoKcGVhay5SQUQyMSA8LSBpbXBvcnRQZWFrKGhlcmUocmVmRGlyLCAiMzMyNTBfUkFEMjFfYWI5OTJfQnJ1Y2UtNF9wZWFrcy5tZXJnZVBlYWsuYmVkIikpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmZsYW5rU2l6ZSA8LSA1MDAwCmdlbmUudGIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJtbTEwX0dSQ20zOC5wNl9nZW5lX3NvcnRlZC5iZWQiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShUU1MgPSBpZmVsc2UoVjQgPT0gIisiLCBWMiwgVjMpLAogICAgICAgICAgICAgICAgVFNTc3RhcnQgPSBUU1MgLSBmbGFua1NpemUsCiAgICAgICAgICAgICAgICBUU1NlbmQgPSBUU1MgKyBmbGFua1NpemUpICU+JQogIGRwbHlyOjpzZWxlY3QoVjYsIFY1LCBWMSwgVFNTc3RhcnQsIFRTU2VuZCkKY29sbmFtZXMoZ2VuZS50YikgPC0gYygiZW5zZW1ibF9nZW5lX2lkIiwgImV4dGVybmFsX2dlbmVfbmFtZSIsICJjaHIiLCAic3RhcnQiLCAiZW5kIikKCgojIENvbnZlcnQgZ2VuZS50YiB0byBhIEdSYW5nZXMgb2JqZWN0CmdlbmVfZ3IgPC0gR1JhbmdlcygKICBzZXFuYW1lcyA9IGdlbmUudGIkY2hyLAogIHJhbmdlcyA9IElSYW5nZXMoc3RhcnQgPSBnZW5lLnRiJHN0YXJ0LCBlbmQgPSBnZW5lLnRiJGVuZCksCiAgZ2VuZV9pZCA9IGdlbmUudGIkZW5zZW1ibF9nZW5lX2lkCikKCiMgQ291bnQgb3ZlcmxhcHMgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMKb3ZlcmxhcF9jb3VudHMgPC0gY291bnRPdmVybGFwcyhnZW5lX2dyLCBwZWFrLlJBRDIxKQoKIyBBZGQgb3ZlcmxhcCBjb3VudHMgdG8gdGhlIG9yaWdpbmFsIGdlbmUudGIgZGF0YQpnZW5lLnRiJHBlYWtfY291bnQgPC0gb3ZlcmxhcF9jb3VudHMKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnBlYWtOdW0wIDwtIChnZW5lLnRiICU+JSBkcGx5cjo6ZmlsdGVyKHBlYWtfY291bnQgPT0gMCkpJGVuc2VtYmxfZ2VuZV9pZApwZWFrTnVtMSA8LSAoZ2VuZS50YiAlPiUgZHBseXI6OmZpbHRlcihwZWFrX2NvdW50ID09IDEpKSRlbnNlbWJsX2dlbmVfaWQKcGVha051bTIgPC0gKGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIocGVha19jb3VudCA9PSAyKSkkZW5zZW1ibF9nZW5lX2lkCnBlYWtOdW0zIDwtIChnZW5lLnRiICU+JSBkcGx5cjo6ZmlsdGVyKHBlYWtfY291bnQgPT0gMykpJGVuc2VtYmxfZ2VuZV9pZApwZWFrTnVtT3ZlcjQgPC0gKGdlbmUudGIgJT4lIGRwbHlyOjpmaWx0ZXIocGVha19jb3VudCA+PSA0KSkkZW5zZW1ibF9nZW5lX2lkCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpuYW1lIDwtICJjaHJvbW9fY29uc19hbm5vSGllcmFyY2h5IgoKYWxwaGEgPC0gMC4wNQpmY0N1dG9mZiA8LSAwLjUKZGlmZi5STkEuRzEuZFRBRyA8LSBmcmVhZChoZXJlKHJlZkRpciwgImRpZmZfRzEuZFRBR19HMS4yaS5kVEFHX3ZzX0cxLjJpLkRNU08udHN2IikpICU+JQogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IGFscGhhLCBhYnMoc2hyaW5rZWRfbG9nMkZDKSA+IGZjQ3V0b2ZmKQpkaWZmLlJOQS5HMS5kVEFHLm5vRkNjdXRvZmYgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCBhbHBoYSkKZ2VuZUFubm9EYXRhIDwtIGxvYWRMb29wQW5ub0RhdGEoaGVyZShjb25zZW5zdXNEaXIsIHBhc3RlMChuYW1lLCAiX3Atbl9lbnNlbWJsTGlzdC50c3YiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZkN1dG9mZiA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vTGlzdCA9IGMoIlAtUCIsICJQLUUiLCAiUC1TIiwgIlAtWCIpKSU+JSAKICBkcGx5cjo6bXV0YXRlKGRpc3RhbmNlID0gc3RhcnQyIC0gc3RhcnQxLAogICAgICAgICAgICAgICAgcGVha0lEID0gcGFzdGUoY2hyb20xLCBzdGFydDEsIHN0YXJ0Miwgc2VwID0gIl8iKSkKCgojIyBEaXZpZGluZyBnZW5lcyBpbnRvIGdyb3Vwcwp0ZW1wIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OnNlbGVjdChkaWZmX2RUQUdfRE1TTywgZGlzdGFuY2UsIGdlbmUpICU+JSAKICB1bm5lc3QoZ2VuZSkgJT4lIGdyb3VwX2J5KGdlbmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RpZmZfc2NvcmUgPSBtZWFuKGRpZmZfZFRBR19ETVNPKSwKICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oZGlzdGFuY2UpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQoKZGlmZi5STkEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJkaWZmX0cxLmRUQUdfRzEuMmkuZFRBR192c19HMS4yaS5ETVNPLnRzdiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgbG9nMkZvbGRDaGFuZ2UsIHNocmlua2VkX2xvZzJGQywgcGFkaiwgZXh0ZXJuYWxfZ2VuZV9uYW1lKQoKbWF4TG9nMkZDID0gMgoKdGVtcCA8LSBsZWZ0X2pvaW4odGVtcCwgZGlmZi5STkEsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBkcGx5cjo6bXV0YXRlKGZsYWcgPSBpZmVsc2UoZ2VuZSAlaW4lIGRpZmYuUk5BLkcxLmRUQUckZW5zZW1ibF9nZW5lX2lkLCAiMkRPV04iLCAiME5PIiksCiAgICAgICAgICAgICAgICBtYXhGbGFnID0gKGFicyhzaHJpbmtlZF9sb2cyRkMpID4gbWF4TG9nMkZDKSwKICAgICAgICAgICAgICAgIGxvZzJmY01heCA9IHBtYXgocG1pbihzaHJpbmtlZF9sb2cyRkMsIG1heExvZzJGQyksIC1tYXhMb2cyRkMpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UoZmxhZykgJT4lCiAgZHJvcF9uYShzaHJpbmtlZF9sb2cyRkMpCgp0ZW1wIDwtIHRlbXAgJT4lIGRwbHlyOjptdXRhdGUoCiAgcG5PdmVyID0gaWZlbHNlKGdlbmUgJWluJSBwZWFrTnVtMCwgInBlYWtOdW0wIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwZWFrTnVtMSwgInBlYWtOdW0xIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgcGVha051bTIsICJwZWFrTnVtMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwZWFrTnVtMywgInBlYWtOdW0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdlbmUgJWluJSBwZWFrTnVtT3ZlcjQsICJwZWFrTnVtT3ZlcjQiLCBOQSkpKSkpKSAlPiUKICBkcm9wX25hKHBuT3ZlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDaGVja2luZyBwZXJjZW50YWdlIG9mIGdlbmVzIHdpdGggUkFEMjEgcGVha3MKZ3JvdXAxIDwtIGZyZWFkKGhlcmUocmVmRGlyLCAiZ2VuZUxpc3RfZFRBR192c19ETVNPX1JOQV9sb29wX2JpbmFyeUdyb3VwMS50c3YiKSkkZ2VuZQpncm91cDIgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAyLnRzdiIpKSRnZW5lCgphYWEgPC0gdGVtcCAlPiUgZHBseXI6Om11dGF0ZShncm91cCA9IGNhc2Vfd2hlbigKICBnZW5lICVpbiUgZ3JvdXAxIH4gImdyb3VwMSIsCiAgZ2VuZSAlaW4lIGdyb3VwMiB+ICJncm91cDIiLAogIFRSVUUgfiBOQQopKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdyb3VwLCBwbk92ZXIsIGdlbmUpICU+JQogIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgJWluJSBjKCJncm91cDEiLCAiZ3JvdXAyIikpICU+JQogIGRwbHlyOjptdXRhdGUoaGFzUGVhayA9IGlmZWxzZShwbk92ZXIgPT0gInBlYWtOdW0wIiwgRkFMU0UsIFRSVUUpKQoKYmJiIDwtIGFhYSAlPiUgZHBseXI6OmZpbHRlcihncm91cCA9PSAiZ3JvdXAxIikgCgpzdW0oYmJiJGhhc1BlYWspCmJiYiA8LSBhYWEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gImdyb3VwMiIpIApzdW0oYmJiJGhhc1BlYWspCgphYWFfc3VtbWFyeSA8LSBhYWEgJT4lCiAgZ3JvdXBfYnkoZ3JvdXAsIHBuT3ZlcikgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBDcmVhdGUgdGhlIHN0YWNrZWQgYmFycGxvdAphYWFfc3VtbWFyeSA8LSBhYWEgJT4lCiAgZ3JvdXBfYnkoZ3JvdXAsIHBuT3ZlcikgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgbXV0YXRlKHJhdGlvID0gY291bnQgLyBzdW0oY291bnQpKQoKIyBEZWZpbmUgdGhlIGdyYWRpZW50IGNvbG9ycwpncmFkaWVudF9jb2xvcnMgPC0gYygiI0Q0RDRENCIsICIjRENCMEFGIiwgIiNFNDhEOEEiLCAiI0VDNjk2NSIsICIjRjQ0NjQxIikKIyBncmFkaWVudF9jb2xvcnMgPC0gYygiI0Q0RDRENCIsICIjQTJCQkNBIiwgIiM3MUEyQzAiLCAiIzNGODlCNyIsICIjMEU3MUFEIikKCiMgQ3JlYXRlIHRoZSBzdGFja2VkIGJhcnBsb3Qgd2l0aCBncmFkaWVudCBjb2xvcnMKcCA8LSBnZ3Bsb3QoYWFhX3N1bW1hcnksIGFlcyh4ID0gZ3JvdXAsIHkgPSByYXRpbywgZmlsbCA9IHBuT3ZlcikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siLAogICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGxhYnMoeCA9IE5VTEwgLCB5ID0gIlJhdGlvIikgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZ3JhZGllbnRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZCgKICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC41KSwgIyBBZGp1c3QgbGVnZW5kIGtleSBzeW1ib2wgc2l6ZQogICAgICBrZXl3aWR0aCA9IDIgLyAyLjU0LCAjIENvbnZlcnQgMm1tIHRvIGNtCiAgICAgIGtleWhlaWdodCA9IDIgLyAyLjU0ICMgQ29udmVydCAybW0gdG8gY20KICAgICkpIAoKd2lkdGggPC0gcGFuZWxTaXplKDEuNykqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjMpKm1tVG9JbmNoCmZpbGVOYW1lIDwtIHBhc3RlMCgicmFkMjFwZXJjX3Byb21vdGVyIikKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpICAKCmBgYAoKIyMjIyMgbG9vcCBzY29yZQpgYGB7cn0KZ2V0UHZhbFdpbGNveCA8LSBmdW5jdGlvbihkYXRhLCBncm91cDEsIGdyb3VwMil7CiAgZGlzdGFuY2UxIDwtIChkYXRhICU+JSBkcGx5cjo6ZmlsdGVyKHBuT3ZlciA9PWdyb3VwMSkgKSRtZWFuX2RpZmZfc2NvcmUKICBkaXN0YW5jZTIgPC0gKGRhdGEgJT4lIGRwbHlyOjpmaWx0ZXIocG5PdmVyID09Z3JvdXAyKSApJG1lYW5fZGlmZl9zY29yZQogIHdpbCA8LSB3aWxjb3gudGVzdChkaXN0YW5jZTEsIGRpc3RhbmNlMikKICByZXR1cm4od2lsJHAudmFsdWUpCn0KCnBzMDEgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVha051bTAiLCAicGVha051bTEiKSwgNSkKcHMxMiA8LSByb3VuZChnZXRQdmFsV2lsY294KHRlbXAsICJwZWFrTnVtMSIsICJwZWFrTnVtMiIpLCA1KQpwczIzIDwtIHJvdW5kKGdldFB2YWxXaWxjb3godGVtcCwgInBlYWtOdW0yIiwgInBlYWtOdW0zIiksIDUpCnBzMzQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVha051bTMiLCAicGVha051bU92ZXI0IiksIDUpCnBzMjQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVha051bTIiLCAicGVha051bU92ZXI0IiksIDUpCnBzMTQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVha051bTEiLCAicGVha051bU92ZXI0IiksIDUpCnBzMDQgPC0gcm91bmQoZ2V0UHZhbFdpbGNveCh0ZW1wLCAicGVha051bTAiLCAicGVha051bU92ZXI0IiksIDUpCgoKcCA8LSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBwbk92ZXIsIHkgPSBtZWFuX2RpZmZfc2NvcmUpKSArIAogIGdlb21fdmlvbGluKGFlcyhmaWxsID0gcG5PdmVyKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIiwKICAgICAgICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BCiAgKSArIHRoZW1lX2NsYXNzaWMoKSArIGxhYnMoeCA9IE5VTEwgLCB5ID0gIkF2ZXJhZ2UgzpQgbG9vcCBzY29yZSIpICsKICBzdGF0X3N1bW1hcnkoCiAgICBhZXMoZ3JvdXAgPSBwbk92ZXIpLCBmdW4gPSBtZWFuLAogICAgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjEsIHNpemUgPSAwLjUsCiAgICBmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0KSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVNLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsIGZhbWlseSA9IGZvbnRUeXBlLCBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICBhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMQogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsIHNpemUgPSBsaW5lVGhpY2sgKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUykKICApKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEsIHkgPSAwLCBsYWJlbCA9IHBhc3RlMCgicHMwMTogIiwgY29udlB2YWx1ZShwczAxKSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMTI6ICIsIGNvbnZQdmFsdWUocHMxMiksICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwczIzOiAiLCBjb252UHZhbHVlKHBzMjMpLCAiXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMzNDogIiwgY29udlB2YWx1ZShwczM0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMjQ6ICIsIGNvbnZQdmFsdWUocHMyNCksICJcbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHMxNDogIiwgY29udlB2YWx1ZShwczE0KSwgIlxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBzMDQ6ICIsIGNvbnZQdmFsdWUocHMwNCksICJcbiIpLCAKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGhqdXN0ID0gMCwgc2l6ZSA9IDIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM3Nzc3NzciLCAiIzhCN0U2NSIsICIjQTI4NDUyIiwgIiNDMjg4NEQiLCAiI0YyOEUyQyIpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDAuMSkpCgoKCmZpbGVOYW1lIDwtIHBhc3RlMCgiZGlmZlNjb3JlX2JhcnBsb3RfUkFEMjFwZWFrV2l0aGluMTBrYl9kVEFHX3ZzX0RNU08iKQp3aWR0aCA8LSAzMyptbVRvSW5jaApoZWlnaHQgPC0zOCptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQpgYGAKCiMjIyMjIGxvZzJGQwpgYGB7cn0KdGVtcCA8LSB0ZW1wICU+JSBkcGx5cjo6bXV0YXRlKGFic0xvZzJGQyA9IGFicyhsb2cyRm9sZENoYW5nZSkpCnAgPC0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gYWJzTG9nMkZDLCBjb2xvciA9IHBuT3ZlcikpICsKc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IChjKCIjNzc3Nzc3IiwgIiM4QjdFNjUiLCAiI0EyODQ1MiIsICIjQzI4ODREIiwgIiNGMjhFMkMiKSkpICsKICBzdGF0X2VjZGYoc2l6ZSA9IDAuNCwgbGluZXdpZHRoID0gbGluZU1lZGl1bSAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiICkgKyAjIFVzZSBzdGF0X2VjZGYgdG8gcGxvdCB0aGUgZW1waXJpY2FsIENERgogIGxhYnMoCiAgICB4ID0gIkFicy4gbG9nMihmb2xkIGNoYW5nZSkiLAogICAgeSA9ICJDdW11bGF0aXZlIFByb2JhYmlsaXR5IgogICkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMS41KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArICMgQ2xlYW4gdGhlbWUKICB0aGVtZSgKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gZm9udFNpemVNLAogICAgICBmYW1pbHkgPSBmb250VHlwZSwKICAgICAgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSBmb250U2l6ZVMsCiAgICAgIGZhbWlseSA9IGZvbnRUeXBlLAogICAgICBjb2xvciA9ICIjMDAwMDAwIgogICAgKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgKICAgICAgY29sb3IgPSAiIzAwMDAwMCIsCiAgICAgIHNpemUgPSBsaW5lVGhpY2sqbW1Ub0xpbmVVbml0LAogICAgICBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwKICAgICAgc2l6ZSA9IGxpbmVUaGljayptbVRvTGluZVVuaXQsCiAgICAgIGxpbmVlbmQgPSAic3F1YXJlIgogICAgKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IGZvbnRUeXBlLCBzaXplID0gZm9udFNpemVTKQogICAgKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEpKQpmaWxlTmFtZSA8LSBwYXN0ZTAoImxvZzJGQ19jZGZfcHNHcm91cF9kVEFHX3ZzX0RNU08iKQp3aWR0aCA8LSAzMyptbVRvSW5jaApoZWlnaHQgPC0zMyptbVRvSW5jaApwbmcoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5wbmciKSksIHJlcyA9IDYwMCwgdW5pdCA9ICJpbiIsIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKQoKYGBgCgojIyMgWzMuNDRdIENoZWNraW5nIFJBRDIxIHBlYWsgZGVuc2l0eSBhdCBncm91cDEgYW5kIGdyb3VwMiBwcm9tb3RlcgpgYGB7cn0KCnBlYWsuUkFEMjEgPC0gaW1wb3J0UGVhayhoZXJlKHJlZkRpciwgIjMzMjUwX1JBRDIxX2FiOTkyX0JydWNlLTRfcGVha3MubWVyZ2VQZWFrLmJlZCIpKQpncm91cDEgPC0gZnJlYWQoaGVyZShyZWZEaXIsICJnZW5lTGlzdF9kVEFHX3ZzX0RNU09fUk5BX2xvb3BfYmluYXJ5R3JvdXAxLnRzdiIpKSRnZW5lCmdyb3VwMiA8LSBmcmVhZChoZXJlKHJlZkRpciwgImdlbmVMaXN0X2RUQUdfdnNfRE1TT19STkFfbG9vcF9iaW5hcnlHcm91cDIudHN2IikpJGdlbmUKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm5hbWUgPC0gImNocm9tb19jb25zX2Fubm9IaWVyYXJjaHkiCgpnZW5lQW5ub0RhdGEgPC0gbG9hZExvb3BBbm5vRGF0YShoZXJlKGNvbnNlbnN1c0RpciwgcGFzdGUwKG5hbWUsICJfcC1uX2Vuc2VtYmxMaXN0LnRzdiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWZmQ3V0b2ZmID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9MaXN0ID0gYygiUC1FIikpCgp0ZW1wMSA8LSBnZW5lQW5ub0RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQTEgPT0gIkUiKSAlPiUgZHBseXI6OnNlbGVjdChjaHJvbTEsIHN0YXJ0MSwgZW5kMSwgZ2VuZSkKY29sbmFtZXModGVtcDEpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiLCAiZ2VuZSIpCnRlbXAyIDwtIGdlbmVBbm5vRGF0YSAlPiUgZHBseXI6OmZpbHRlcihBMiA9PSAiRSIpICU+JSBkcGx5cjo6c2VsZWN0KGNocm9tMiwgc3RhcnQyLCBlbmQyLCBnZW5lKQpjb2xuYW1lcyh0ZW1wMikgPC0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJnZW5lIikKCmVuaEFuY2hvcnMgPC0gYmluZF9yb3dzKHRlbXAxLCB0ZW1wMikgJT4lIHVubmVzdChnZW5lKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgZ3JvdXAgPSBjYXNlX3doZW4oCiAgICAgIGdlbmUgJWluJSBncm91cDEgfiAiR3JwMSIsCiAgICAgIGdlbmUgJWluJSBncm91cDIgfiAiR3JwMiIsCiAgICAgIFRSVUUgfiBOQQogICAgKQogICkgJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGdyb3VwKSkKCmVuaCA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoZW5oQW5jaG9ycyAlPiUgZHBseXI6OnNlbGVjdChjKDEsIDIsIDMpKSkKCiMgQ291bnQgb3ZlcmxhcHMgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMKb3ZlcmxhcF9jb3VudHMgPC0gY291bnRPdmVybGFwcyhlbmgsIHBlYWsuUkFEMjEpCgojIEFkZCBvdmVybGFwIGNvdW50cyB0byB0aGUgb3JpZ2luYWwgZ2VuZS50YiBkYXRhCmVuaEFuY2hvcnMkcGVha19jb3VudCA8LSBvdmVybGFwX2NvdW50cwoKZW5oQW5jaG9ycyA8LSBlbmhBbmNob3JzICU+JSBkcGx5cjo6bXV0YXRlKAogIHBlYWtHcm91cCA9IGNhc2Vfd2hlbigKICAgIHBlYWtfY291bnQgPT0gMCB+ICJwZWFrTnVtMCIsCiAgICBwZWFrX2NvdW50ID09IDEgfiAicGVha051bTEiLAogICAgcGVha19jb3VudCA9PSAyIH4gInBlYWtOdW0yIiwKICAgIHBlYWtfY291bnQgPT0gMyB+ICJwZWFrTnVtMyIsCiAgICBwZWFrX2NvdW50ID49IDQgfiAicGVha051bU92ZXI0IgogICkKKQoKYWFhIDwtIGVuaEFuY2hvcnMgJT4lIAogIGRwbHlyOjpzZWxlY3QoZ3JvdXAsIHBlYWtHcm91cCwgZ2VuZSkgJT4lCiAgZHBseXI6Om11dGF0ZShoYXNQZWFrID0gaWZlbHNlKHBlYWtHcm91cCA9PSAicGVha051bTAiLCBGQUxTRSwgVFJVRSkpCgpiYmIgPC0gYWFhICU+JSBkcGx5cjo6ZmlsdGVyKGdyb3VwID09ICJHcnAxIikgCnN1bShiYmIkaGFzUGVhaykvbnJvdyhiYmIpCmJiYiA8LSBhYWEgJT4lIGRwbHlyOjpmaWx0ZXIoZ3JvdXAgPT0gIkdycDIiKSAKc3VtKGJiYiRoYXNQZWFrKS9ucm93KGJiYikKCgphYWFfc3VtbWFyeSA8LSBhYWEgJT4lCiAgZ3JvdXBfYnkoZ3JvdXAsIHBlYWtHcm91cCkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBDcmVhdGUgdGhlIHN0YWNrZWQgYmFycGxvdAphYWFfc3VtbWFyeSA8LSBhYWEgJT4lCiAgZ3JvdXBfYnkoZ3JvdXAsIHBlYWtHcm91cCkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBncm91cF9ieShncm91cCkgJT4lCiAgbXV0YXRlKHJhdGlvID0gY291bnQgLyBzdW0oY291bnQpKQoKIyBEZWZpbmUgdGhlIGdyYWRpZW50IGNvbG9ycwojIGdyYWRpZW50X2NvbG9ycyA8LSBjKCIjRDRENEQ0IiwgIiNEQ0IwQUYiLCAiI0U0OEQ4QSIsICIjRUM2OTY1IiwgIiNGNDQ2NDEiKQpncmFkaWVudF9jb2xvcnMgPC0gYygiI0Q0RDRENCIsICIjQTJCQkNBIiwgIiM3MUEyQzAiLCAiIzNGODlCNyIsICIjMEU3MUFEIikKCiMgQ3JlYXRlIHRoZSBzdGFja2VkIGJhcnBsb3Qgd2l0aCBncmFkaWVudCBjb2xvcnMKcCA8LSBnZ3Bsb3QoYWFhX3N1bW1hcnksIGFlcyh4ID0gZ3JvdXAsIHkgPSByYXRpbywgZmlsbCA9IHBlYWtHcm91cCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siLAogICAgICAgICAgIGxpbmV3aWR0aCA9IGxpbmVNZWRpdW0gKiBtbVRvTGluZVVuaXQsIGxpbmVlbmQgPSAic3F1YXJlIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIGxhYnMoeCA9IE5VTEwgLCB5ID0gIlJhdGlvIikgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IGZvbnRTaXplTSwgZmFtaWx5ID0gZm9udFR5cGUsIGNvbG9yID0gIiMwMDAwMDAiCiAgICApLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gZm9udFNpemVTLCBmYW1pbHkgPSBmb250VHlwZSwgY29sb3IgPSAiIzAwMDAwMCIKICAgICksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoCiAgICAgIGNvbG9yID0gIiMwMDAwMDAiLCBzaXplID0gbGluZVRoaWNrICogbW1Ub0xpbmVVbml0LCBsaW5lZW5kID0gInNxdWFyZSIKICAgICksCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKAogICAgICBjb2xvciA9ICIjMDAwMDAwIiwgc2l6ZSA9IGxpbmVUaGljayAqIG1tVG9MaW5lVW5pdCwgbGluZWVuZCA9ICJzcXVhcmUiCiAgICApLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBmb250VHlwZSwgc2l6ZSA9IGZvbnRTaXplUyksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gZm9udFR5cGUsIHNpemUgPSBmb250U2l6ZVMpCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZ3JhZGllbnRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZCgKICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC41KSwgIyBBZGp1c3QgbGVnZW5kIGtleSBzeW1ib2wgc2l6ZQogICAgICBrZXl3aWR0aCA9IDIgLyAyLjU0LCAjIENvbnZlcnQgMm1tIHRvIGNtCiAgICAgIGtleWhlaWdodCA9IDIgLyAyLjU0ICMgQ29udmVydCAybW0gdG8gY20KICAgICkpIAoKd2lkdGggPC0gcGFuZWxTaXplKDEuNykqbW1Ub0luY2gKaGVpZ2h0IDwtIHBhbmVsU2l6ZSgxLjMpKm1tVG9JbmNoCmZpbGVOYW1lIDwtIHBhc3RlMCgicmFkMjFwZXJjX2VuaCIpCnN2Z2xpdGUoaGVyZShmaWdEaXIsIHBhc3RlMChmaWxlTmFtZSwgIi5zdmciKSksICBoZWlnaHQgPSBoZWlnaHQsIHdpZHRoID0gd2lkdGgpCnByaW50KHApCmRldi5vZmYoKSAgCgpgYGAKCiMgTk9UIENPTkNMVVNJVkUgQkVMT1cgSEVSRQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3J9CgpkYXRhIDwtIGZyZWFkKGhlcmUocmVzdWx0RGlyLCAiY2hyb21ITU0iLCAiQTQ4NV9wZS1wZV9hbmNob3JzIiwgIm92ZXJsYXBfZW5yaWNoXzEwMF9zdGF0ZS50eHQiKSkKY29sbmFtZXMoZGF0YSkgPC0gYygic3RhdGUiLCAiZ2Vub21lIiwgInBlLXBlX0E0ODVfZG93biIsICJwZS1wZV9BNDg1X25vIiwgInBlLXBlX0E0ODVfdXAiKQpkYXRhIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoLWdlbm9tZSkgJT4lIGFzLm1hdHJpeCgpCgogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAic3RhdGUiKSAlPiUKICBhcy5tYXRyaXgoKQoKbGlicmFyeShjaXJjbGl6ZSkKCmNvbF9mdW4gPC0gY29sb3JSYW1wMihjKDAsIDEsIDEwKSwgCiAgICAgICAgICAgICAgICAgICAgICBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQoKbGlicmFyeShjaXJjbGl6ZSkKY29sX2Z1biA8LSBjb2xvclJhbXAyKGMobWluKGRhdGEpLCBtYXgoZGF0YSkpLCBjKCJ3aGl0ZSIsICJyZWQiKSkKCgojZnZpel9uYmNsdXN0KGRhdGEsIGttZWFucywgbWV0aG9kID0gIndzcyIpCgpwIDwtIEhlYXRtYXAoCiAgZGF0YSwKICBuYW1lID0gIk9kZHMgUmF0aW8iLCAgICAgICAgICAgICAgICAgICAjIE5hbWUgb2YgdGhlIGhlYXRtYXAgbGVnZW5kCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICAgICAgICAgICAgIyBSZW1vdmUgY29sdW1uIGRlbmRyb2dyYW0KICByb3dfa20gPSAxMCwgICAgICAgICAgICAgICAgICAgICAgICAgIyBEZWZpbmUgdGhlIG51bWJlciBvZiBrLW1lYW5zIGNsdXN0ZXJzIGZvciByb3dzIChhZGp1c3QgYXMgbmVlZGVkKQogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBjb2wgPSBjb2xfZnVuLAogIGJvcmRlciA9IFRSVUUKKQoKZmlsZU5hbWUgPC0gcGFzdGUwKCJhbmNob3JMT0xBX2RUQUdfdnNfRE1TT19kaWZmMC4yX2FsbExvb3BzX2V4dHJlbWVfcmVnQW5jaG9yQmFja2dyb3VuZF9hdGFjIikKaGVpZ2h0IDwtIDcKd2lkdGggPC0gMy41CnBuZyhoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnBuZyIpKSwgcmVzID0gNjAwLCB1bml0ID0gImluIiwgaGVpZ2h0ID0gaGVpZ2h0LCB3aWR0aCA9IHdpZHRoKQpwcmludChwKQpkZXYub2ZmKCkKc3ZnbGl0ZShoZXJlKGZpZ0RpciwgcGFzdGUwKGZpbGVOYW1lLCAiLnN2ZyIpKSwgIGhlaWdodCA9IGhlaWdodCwgd2lkdGggPSB3aWR0aCkKcHJpbnQocCkKZGV2Lm9mZigpCgpgYGAKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoK